|
|
|
|
@ -1,8 +1,14 @@
|
|
|
|
|
import 'dart:async';
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:developer';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesfit_devices/all_in_one_monitor/check_me_response.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesfit_devices/all_in_one_monitor/device_info.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesfit_devices/all_in_one_monitor/end_read_pkg.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesfit_devices/all_in_one_monitor/read_content_pkg.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesfit_devices/all_in_one_monitor/start_read_pkg.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesfit_devices/bt_constants.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/andesfit_devices/weight_data_model.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/andesfit_devices/weight_data_model.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart';
|
|
|
|
|
@ -67,7 +73,7 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
{"model": "BLE-MSA"},
|
|
|
|
|
],
|
|
|
|
|
"AllInOneTracker": [
|
|
|
|
|
{"model": ""},
|
|
|
|
|
{"model": "Checkme 1316"},
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@ -94,12 +100,12 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
{"model": "BLE-MSA"},
|
|
|
|
|
],
|
|
|
|
|
"AllInOneTracker": [
|
|
|
|
|
{"model": ""},
|
|
|
|
|
{"model": "Checkme 1316"},
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
List<String> ecgEnabledDevices = ["BP2 0567", "DuoEK", "ER1", "PM101897"];
|
|
|
|
|
List<String> andesFitDevices = ["BPM", "PM101897", "SDIC", "TEMP", "Samico GL", "BLE-MSA"];
|
|
|
|
|
List<String> andesFitDevices = ["BPM", "PM101897", "SDIC", "TEMP", "Samico GL", "BLE-MSA", "Checkme 1316"];
|
|
|
|
|
|
|
|
|
|
StreamSubscription bleDevicesStream;
|
|
|
|
|
|
|
|
|
|
@ -260,8 +266,9 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
List devicesInSelectedType = devicesInfoJsonAndesfit[currentSelectedTrackerType.name];
|
|
|
|
|
for (var foundDevice in allDevices) {
|
|
|
|
|
for (var device in devicesInSelectedType) {
|
|
|
|
|
if (isAndesfitDeviceConnected != null && isAndesfitDeviceConnected) {
|
|
|
|
|
return;
|
|
|
|
|
if (isDeviceSelected) {
|
|
|
|
|
log("CONNECTED, Breaking the loop");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
foundDevice.deviceType = currentSelectedTrackerType;
|
|
|
|
|
log("here1: ${device['model']}");
|
|
|
|
|
@ -380,6 +387,7 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> disConnectDevice() async {
|
|
|
|
|
isDeviceSelected = false;
|
|
|
|
|
await BleChannel.disconnect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -402,6 +410,8 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
FlutterBluePlus.stopScan();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
log("blueToothDevicesLength : ${blueToothDevices.length}");
|
|
|
|
|
|
|
|
|
|
blueToothDevices.forEach((element) async {
|
|
|
|
|
if (element.device.localName.isNotEmpty) {
|
|
|
|
|
log("blueToothDevicesFlutter: ${element.device.localName}");
|
|
|
|
|
@ -411,8 +421,9 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
});
|
|
|
|
|
filterOutTheSearchedDevicesFlutter(bleDevices);
|
|
|
|
|
});
|
|
|
|
|
FlutterBluePlus.startScan(timeout: const Duration(seconds: 10), androidUsesFineLocation: false,
|
|
|
|
|
// withServices: [Guid(BLEUtils.TEMPERATURE_SERVICE)]
|
|
|
|
|
FlutterBluePlus.startScan(
|
|
|
|
|
timeout: const Duration(seconds: 10), androidUsesFineLocation: false,
|
|
|
|
|
// withServices: [Guid(BLEUtils.TEMPERATURE_SERVICE)]
|
|
|
|
|
).catchError((err) {
|
|
|
|
|
debugPrint(err.toString());
|
|
|
|
|
});
|
|
|
|
|
@ -599,6 +610,8 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
String resultSet1 = "";
|
|
|
|
|
String resultSet2 = "";
|
|
|
|
|
|
|
|
|
|
String resultSetCheckMeProUsers = "";
|
|
|
|
|
|
|
|
|
|
Future<void> connectAndesfitWeightDevice(BluetoothDevice device) async {
|
|
|
|
|
log("deviceToConnect: ${device.toString()}");
|
|
|
|
|
|
|
|
|
|
@ -727,6 +740,36 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
updateAndesfitWeightScaleData(WeightScaleData(weight: weight, bmi: bmi, fat: fat, muscle: muscle, bmr: bmr, bone: bone, water: water));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void parseResultDataTest() {
|
|
|
|
|
List<String> hexStringResSet1 = resultSet1.split(";");
|
|
|
|
|
List<String> hexStringResSet2 = resultSet2.split(";");
|
|
|
|
|
|
|
|
|
|
String hexStringWeight = adjustHexString(hexStringResSet1[13]) + adjustHexString(hexStringResSet1[14]);
|
|
|
|
|
String hexStringBMI = adjustHexString(hexStringResSet1[15]) + adjustHexString(hexStringResSet1[16]);
|
|
|
|
|
String hexStringFat = adjustHexString(hexStringResSet2[3]) + adjustHexString(hexStringResSet2[4]);
|
|
|
|
|
String hexStringBone = adjustHexString(hexStringResSet2[11]) + adjustHexString(hexStringResSet2[12]);
|
|
|
|
|
String hexStringWater = adjustHexString(hexStringResSet2[13]) + adjustHexString(hexStringResSet2[14]);
|
|
|
|
|
String hexStringMuscle = adjustHexString(hexStringResSet2[7]) + adjustHexString(hexStringResSet2[8]);
|
|
|
|
|
String hexStringBMR = adjustHexString(hexStringResSet2[9]) + adjustHexString(hexStringResSet2[10]);
|
|
|
|
|
|
|
|
|
|
print((int.parse(hexStringWeight, radix: 16) * 0.1).toStringAsFixed(1));
|
|
|
|
|
print((int.parse(hexStringBMI, radix: 16) * 0.1).toStringAsFixed(1));
|
|
|
|
|
print((int.parse(hexStringFat, radix: 16) * 0.1).toStringAsFixed(1));
|
|
|
|
|
print((int.parse(hexStringMuscle, radix: 16) * 0.1).toStringAsFixed(1));
|
|
|
|
|
print((int.parse(hexStringBMR, radix: 16)));
|
|
|
|
|
print((int.parse(hexStringBone, radix: 16) * 0.1).toStringAsFixed(1));
|
|
|
|
|
print((int.parse(hexStringWater, radix: 16) * 0.1).toStringAsFixed(1));
|
|
|
|
|
|
|
|
|
|
var weight = (int.parse(hexStringWeight, radix: 16) * 0.1).toStringAsFixed(1);
|
|
|
|
|
var bmi = (int.parse(hexStringBMI, radix: 16) * 0.1).toStringAsFixed(1);
|
|
|
|
|
var fat = (int.parse(hexStringFat, radix: 16) * 0.1).toStringAsFixed(1);
|
|
|
|
|
var muscle = (int.parse(hexStringMuscle, radix: 16) * 0.1).toStringAsFixed(1);
|
|
|
|
|
var bmr = (int.parse(hexStringBMR, radix: 16)).toString();
|
|
|
|
|
var bone = (int.parse(hexStringBone, radix: 16) * 0.1).toStringAsFixed(1);
|
|
|
|
|
var water = (int.parse(hexStringWater, radix: 16) * 0.1).toStringAsFixed(1);
|
|
|
|
|
updateAndesfitWeightScaleData(WeightScaleData(weight: weight, bmi: bmi, fat: fat, muscle: muscle, bmr: bmr, bone: bone, water: water));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String convertResultSetToString(List<int> byteArray) {
|
|
|
|
|
String resSet;
|
|
|
|
|
resSet = (byteArray.map(
|
|
|
|
|
@ -1006,4 +1049,245 @@ class MyTrackersViewModel extends ChangeNotifier {
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isDeviceSelected = false;
|
|
|
|
|
|
|
|
|
|
List<int> listOutput = [];
|
|
|
|
|
|
|
|
|
|
int cmdState = 0;
|
|
|
|
|
String currentFileName = "usr.dat";
|
|
|
|
|
var currentFileSize = 0;
|
|
|
|
|
int pkgTotal = 0;
|
|
|
|
|
int result = 0;
|
|
|
|
|
int currentPkg = 0;
|
|
|
|
|
|
|
|
|
|
BluetoothCharacteristic allInOneWriteCharacteristics;
|
|
|
|
|
|
|
|
|
|
sendCommand(List<int> bytes) {
|
|
|
|
|
log("trying to write on $allInOneWriteCharacteristics");
|
|
|
|
|
allInOneWriteCharacteristics.write(bytes, withoutResponse: true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> connectAndesfitAllInOneDevice(BluetoothDevice device) async {
|
|
|
|
|
log("deviceToConnect: ${device.toString()}");
|
|
|
|
|
|
|
|
|
|
device.connectionState.listen((BluetoothConnectionState state) async {
|
|
|
|
|
if (state == BluetoothConnectionState.disconnected) {
|
|
|
|
|
isAndesfitDeviceConnected = false;
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
if (state == BluetoothConnectionState.connected) {
|
|
|
|
|
isAndesfitDeviceConnected = true;
|
|
|
|
|
notifyListeners();
|
|
|
|
|
bleDevicesStream.cancel();
|
|
|
|
|
|
|
|
|
|
List<BluetoothService> services = await device.discoverServices();
|
|
|
|
|
services.forEach((service) {
|
|
|
|
|
if (service.serviceUuid.toString().toLowerCase() == BLEUtils.ALL_IN_ONE_SERVICE.toLowerCase()) {
|
|
|
|
|
service.characteristics.forEach((characteristic) async {
|
|
|
|
|
log("characteristics : ${characteristic.characteristicUuid}");
|
|
|
|
|
if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.ALL_IN_ONE_READ_CHARACTERISTIC.toLowerCase()) {
|
|
|
|
|
characteristic.onValueReceived.listen((event) {
|
|
|
|
|
log("onValueReceived 9A57 Stream");
|
|
|
|
|
log(event.toString());
|
|
|
|
|
handleDataPool(event);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await Future.delayed(Duration(milliseconds: 1000)).then((value) async {
|
|
|
|
|
log("-----Delayed 9A57 notify true done-----");
|
|
|
|
|
if (!characteristic.isNotifying) await characteristic.setNotifyValue(true).catchError((err) {});
|
|
|
|
|
});
|
|
|
|
|
} else if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.ALL_IN_ONE_WRITE_CHARACTERISTIC.toLowerCase()) {
|
|
|
|
|
print(characteristic.characteristicUuid);
|
|
|
|
|
print(characteristic.properties.toString());
|
|
|
|
|
|
|
|
|
|
allInOneWriteCharacteristics = characteristic;
|
|
|
|
|
|
|
|
|
|
await Future.delayed(Duration(milliseconds: 3000)).then((value) => getFile("usr.dat"));
|
|
|
|
|
// await Future.delayed(Duration(milliseconds: 3000)).then((value) async {
|
|
|
|
|
// characteristic.write([-86, 3, -4, 0, 0, 8, 0, 117, 115, 114, 46, 100, 97, 116, 0, 124], withoutResponse: true).then((value) {
|
|
|
|
|
// print("----E1A3 get User Info command data written----");
|
|
|
|
|
// });
|
|
|
|
|
// });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await device.connect(timeout: Duration(seconds: 35));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getFile(String fileName) async {
|
|
|
|
|
log("writing command: $fileName");
|
|
|
|
|
log("on characteristic: $allInOneWriteCharacteristics");
|
|
|
|
|
cmdState = 1;
|
|
|
|
|
var pkg = StartReadPkg(fileName);
|
|
|
|
|
log("----- Current PKG ----- ${pkg.buf.toString()}");
|
|
|
|
|
sendCommand(pkg.buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<int> handleDataPool(List<int> bytes) {
|
|
|
|
|
log("bytes I got in dataPool: $bytes");
|
|
|
|
|
var bytesLeft = bytes;
|
|
|
|
|
if (bytes == null || bytes.length < 8) {
|
|
|
|
|
return bytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < bytes.length - 7; i++) {
|
|
|
|
|
if (bytes[i] != 0x55.toByte() || bytes[i + 1] != (bytes[i + 2].inv()).toByte()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// need content length
|
|
|
|
|
var len = bytes.sublist(i + 5, i + 7).toUInt();
|
|
|
|
|
if (i + 8 + len > bytes.length) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var temp = bytes.sublist(i, i + 8 + len);
|
|
|
|
|
if (temp.last == temp.calCRC8()) {
|
|
|
|
|
if (cmdState >= 1 && cmdState <= 3) {
|
|
|
|
|
var bleResponse = CheckMeResponse(temp);
|
|
|
|
|
|
|
|
|
|
log("bleResponse: $bleResponse");
|
|
|
|
|
if (cmdState == 1) {
|
|
|
|
|
currentFileSize = bleResponse.content.toUInt();
|
|
|
|
|
pkgTotal = currentFileSize ~/ 512;
|
|
|
|
|
if (bleResponse.cmd == 1) {
|
|
|
|
|
result = 1;
|
|
|
|
|
var pkg = EndReadPkg();
|
|
|
|
|
sendCommand(pkg.buf);
|
|
|
|
|
cmdState = 3;
|
|
|
|
|
} else if (bleResponse.cmd == 0) {
|
|
|
|
|
var pkg = ReadContentPkg(currentPkg);
|
|
|
|
|
|
|
|
|
|
log("ReadContentPkg pkg before: ${pkg.buf}");
|
|
|
|
|
|
|
|
|
|
if (pkg.buf.last == 204) {
|
|
|
|
|
pkg.buf.last = 106;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log("ReadContentPkg pkg: ${pkg.buf}");
|
|
|
|
|
|
|
|
|
|
//[-86, 4, -5, 0, 0, 0, 204] --> DART
|
|
|
|
|
//[-86, 4, -5, 0, 0, 0, 106] --> KOTLIN
|
|
|
|
|
sendCommand(pkg.buf);
|
|
|
|
|
currentPkg++;
|
|
|
|
|
cmdState = 2;
|
|
|
|
|
}
|
|
|
|
|
} else if (cmdState == 2) {
|
|
|
|
|
// bleResponse.content.apply {
|
|
|
|
|
// fileData = add(fileData, this)
|
|
|
|
|
// fileData?.let {
|
|
|
|
|
// dataScope.launch {
|
|
|
|
|
// fileProgressChannel.send(
|
|
|
|
|
// FileProgress(
|
|
|
|
|
// currentFileName,
|
|
|
|
|
// it.size * 100 / currentFileSize,
|
|
|
|
|
// true
|
|
|
|
|
// )
|
|
|
|
|
// )
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
if (currentPkg > pkgTotal) {
|
|
|
|
|
// fileData?.apply {
|
|
|
|
|
// result = 0
|
|
|
|
|
// Log.i("file", "receive $currentFileName")
|
|
|
|
|
// File(Constant.getPathX(currentFileName)).writeBytes(this)
|
|
|
|
|
// }
|
|
|
|
|
var pkg = EndReadPkg();
|
|
|
|
|
log("file bytes ${pkg.buf}");
|
|
|
|
|
sendCommand(pkg.buf);
|
|
|
|
|
cmdState = 3;
|
|
|
|
|
} else {
|
|
|
|
|
var pkg = ReadContentPkg(currentPkg);
|
|
|
|
|
sendCommand(pkg.buf);
|
|
|
|
|
currentPkg++;
|
|
|
|
|
}
|
|
|
|
|
} else if (cmdState == 3) {
|
|
|
|
|
currentPkg = 0;
|
|
|
|
|
cmdState = 0;
|
|
|
|
|
// dataScope.launch {
|
|
|
|
|
// fileProgressChannel.send(
|
|
|
|
|
// FileProgress(
|
|
|
|
|
// currentFileName,
|
|
|
|
|
// 100,
|
|
|
|
|
// result == 0
|
|
|
|
|
// )
|
|
|
|
|
// )
|
|
|
|
|
// fileChannel.send(result)
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
} else if (cmdState == 4) {
|
|
|
|
|
var deviceInfo = DeviceInfo(temp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<int> tempBytes;
|
|
|
|
|
if (i + 8 + len == bytes.length) {
|
|
|
|
|
tempBytes = null;
|
|
|
|
|
} else {
|
|
|
|
|
tempBytes = bytes.sublist(i + 8 + len, bytes.length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handleDataPool(tempBytes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bytesLeft;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension BTExtensions on int {
|
|
|
|
|
int toByte() {
|
|
|
|
|
const int maxUnsignedByteValue = 255;
|
|
|
|
|
const int maxSignedByteValue = 127;
|
|
|
|
|
const int minSignedByteValue = -128;
|
|
|
|
|
|
|
|
|
|
// Mask out all but the least significant 8 bits
|
|
|
|
|
int maskedValue = this & maxUnsignedByteValue;
|
|
|
|
|
|
|
|
|
|
// Check if the MSB is set (indicating a negative value)
|
|
|
|
|
bool isNegative = maskedValue & (1 << 7) != 0;
|
|
|
|
|
|
|
|
|
|
// If the MSB is set, convert to a signed byte using two's complement
|
|
|
|
|
if (isNegative) {
|
|
|
|
|
// Invert the bits
|
|
|
|
|
maskedValue = ~maskedValue & maxUnsignedByteValue;
|
|
|
|
|
// Add 1 to get the two's complement representation
|
|
|
|
|
maskedValue = (maskedValue + 1) & maxSignedByteValue;
|
|
|
|
|
// Negate the value
|
|
|
|
|
maskedValue *= -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return maskedValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int inv() {
|
|
|
|
|
return ~this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension BTExtensionss on List<int> {
|
|
|
|
|
int toUInt() {
|
|
|
|
|
var result = 0;
|
|
|
|
|
for (var i = 0; i < this.length; i++) {
|
|
|
|
|
result += this[i].toUnsigned(8) << (i * 8);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int calCRC8() {
|
|
|
|
|
if (this == null || this.isEmpty) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
int crc = 0;
|
|
|
|
|
for (int i = 0; i < this.length - 1; i++) {
|
|
|
|
|
crc = BTConstants.Table_CRC8[0xFF & (crc ^ this[i].toByte())];
|
|
|
|
|
}
|
|
|
|
|
return crc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|