// // BluetoothManager.swift // Twear // // Created by yangbin on 2021/12/6. // import Foundation import CoreBluetooth import UIKit import SwiftUI import SwiftDate import AudioToolbox import Alamofire protocol BluetoothManagerDelegate: NSObjectProtocol { func didDiscover(devices: [ScanDevice]) func didConnect(_ peripheral: CBPeripheral) func centralManagerDidUpdateState(_ state: Int) func didDisconnected() } //@objc protocol BluetoothSyncDelegate { // @objc optional func didReceiveFindCommand(status: Bool) // @objc optional func didConnect(_ peripheral: CBPeripheral) //} protocol BluetoothSyncDelegate { func didReceiveFindCommand(status: Bool) func didReceiveHeartRate(value: Int) func didReceiveBloodOxygen() func didReceiveBloodPressure() func didReceiveSettingData() func didReceiveStep() func firstSync() func syncBug() // adapted func didReceiveBattery(value: Int) func didReceiveFindPhoneCommand(value: Int) func didReceiveCallOff() func didReceiveCameraCommand(status: UInt8)// 0x00 进入拍照 0x01 拍照 0x02 关闭 } extension BluetoothSyncDelegate { func didReceiveFindCommand(status: Bool) { } func didReceiveHeartRate(value: Int) { } func didReceiveBloodOxygen() { } func didReceiveBloodPressure() { } func didReceiveSettingData() { } func didReceiveStep() { } func firstSync() {} func syncBug() {} // adapted func didReceiveBattery(value: Int) { } func didReceiveFindPhoneCommand(value: Int) { } func didReceiveCallOff(){ } func didReceiveCameraCommand(status: UInt8) { } } class BluetoothManager: NSObject { //Closure var setCmdClosure: ((_ error: Int?) -> ())? var isManagerSync: Bool = false var setDataClosure: ((_ error: Int?) -> ())? var firmwareCallbackClosure: ((_ version: String, _ type: String, _ updateDic: [String: String], _ error: Int?) -> ())? var firmwareAlert: Bool = true var firmwareAlertView: FirmwareRemindView? var delegateList: [BluetoothManagerDelegate] = [] var syncDelegateList: [BluetoothSyncDelegate] = [] typealias SetCmdSyncClosure = (_ error: Error?) -> Void var setSyncClosure: SetCmdSyncClosure? typealias HeartRateClosure = (_ hrArray: [HeartRateModel], _ error: Int?) -> Void var heartRateClosure: HeartRateClosure? typealias BloodPressureClosure = (_ bpArray: [BloodPressureModel], _ error: Int?) -> Void var bloodPressureClosure: BloodPressureClosure? typealias BloodOxygenClosure = (_ boArray: [BloodOxygenModel], _ error: Int?) -> Void var bloodOxygenClosure: BloodOxygenClosure? typealias SleepClosure = (_ sleepArray: [SleepModel], _ error: Int?) -> Void var sleepClosure: SleepClosure? typealias StepClosure = (_ stepArray: [StepModel], _ error: Int?) -> Void var stepClosure: StepClosure? typealias TrainClosure = (_ trainArray: TrainModel?, _ error: Int?) -> Void var trainClosure: TrainClosure? typealias PressureClosure = (_ pressureArray: [PressureModel], _ error: Int?) -> Void var pressureClosure: PressureClosure? typealias MettClosure = (_ mettArray: [MettModel], _ error: Int?) -> Void var mettClosure: MettClosure? typealias DialProgressClosure = (_ progress: Int) -> Void var dialProgressClosure: DialProgressClosure? typealias DialClosure = (_ error: Int?) -> Void var dialClosure: DialClosure? typealias CustomDialProgressClosure = (_ progress: Int) -> Void var customProgressClosure: DialProgressClosure? typealias CustomDialClosure = (_ error: Int?) -> Void var customClosure: DialClosure? typealias SyncRTKProgressClosure = (_ progress: Int) -> Void var syncRTKProgressClosure: SyncRTKProgressClosure? typealias SyncRTKClosure = (_ error: Error?) -> Void var syncRTKClosure: SyncRTKClosure? typealias ContactProgressClosure = (_ progress: Int) -> Void var contactProgressClosure: ContactProgressClosure? var audioPlayer:AVAudioPlayer = AVAudioPlayer() static let shared = BluetoothManager() // weak var delegate: BluetoothManagerDelegate? var manger: MTKBleManager? var peripheral: CBPeripheral? = nil // private var conPeripheral: CBPeripheral? = nil //已连接的 var platform: Platform = .other //CBCentralManager private var centralManger: CBCentralManager? = nil private var peripheralDic: [String: CBPeripheral] = [:] private var deviceArray: [ScanDevice] = [] private var connectedPerArray: [CBPeripheral] = [] private var contactArray: [ContactModel] = [] //mergeData var totalBytes: [UInt8] = [] var totalLength: Int = 0 var mergeLength: Int = 0 //sync var isSyncReceived: Bool = false //是否收到同步data var isSync: Bool = false //是否在同步中 var isSyncType: SyncType = .other //正在同步的指令 var isNextSync: Bool = false //是否有下一个同步包 // private var override init() { super.init() // manger.registerClientProfile(BLEConfig.MTKServerUUID, clientProfileDelegate: self) // manger.registerClientProfile(BLEConfig.MTKBasServerUUID, clientProfileDelegate: self) // manger.registerClientProfile(BLEConfig.MTKDialServerUUID, clientProfileDelegate: self) // FmpGattClient.getInstance() manger = MTKBleManager.sharedInstance() as? MTKBleManager platform = CurDevice.platform setupManger(nil) // registerClientProfile() } private func setupManger(_ peripheral: CBPeripheral?) { if peripheral == nil { if CurDevice.uuid == "" { return } else { registerClientProfile() } } else { registerClientProfile() } } private func registerClientProfile() { switch platform { case ._828: manger?.registerClientProfile(BLEConfig.ServerUUID, clientProfileDelegate: self) default: break } } func registerDelegate(_ delegate: BluetoothManagerDelegate) { delegateList.append(delegate) print(delegateList) // print(NSStringFromClass(type(of: delegate))) } func unRegisterDelegate(_ delegate: BluetoothManagerDelegate) { delegateList.removeAll{ type(of: $0) == type(of: delegate) } } func registerSyncDelegate(_ delegate: BluetoothSyncDelegate) { syncDelegateList.append(delegate) } func unRegisterSyncDelegate(_ delegate: BluetoothSyncDelegate) { syncDelegateList.removeAll{ type(of: $0) == type(of: delegate) } } func clearDelegate() { delegateList.removeAll() syncDelegateList.removeAll() } func startScanning() { print("jason_bluetooth_action_0:开始扫描") peripheralDic = [:] deviceArray = [] centralManger = CBCentralManager(delegate: self, queue: nil) manger?.startScanning() //mClientProfileDic __NSDictionaryM * 1 key/value pair 0x0000000281a694c0 } func stopScanning() { if centralManger != nil { if centralManger!.isScanning { centralManger?.stopScan() } centralManger = nil } manger?.stopScanning() } func connect(peripheral: CBPeripheral) { print("jason_bluetooth_action_2:发起连接"); // setupManger(peripheral) let name = peripheral.name // 这里是根据名字来判断其平台类型 platform = ._828 registerClientProfile() manger?.connectPeripheral(peripheral) } func reconnectPer() { if self.peripheral != nil { connect(peripheral: self.peripheral!) } } func reConnect() { startScanning() } func forgetPeripheral() { print("forgetPeripheral") manger?.forgetPeripheral() // let menstrual = .menstrual manger = nil // MTKBleManager.sharedInstance() = nil manger = MTKBleManager.sharedInstance() as? MTKBleManager OTAPeripheral = nil peripheral = nil let device = DeviceModel() // device.menstrual = menstrual AdminHelper.shared.updateDevice(device) } func disconnect() { for per in connectedPerArray { manger?.disconnectPeripheral(per) } // manger.disconnectPeripheral() // manger.foundPeripherals = [] // manger.connectPeripherals = [] // manger.connectedService = [] // manger.tempPeripheral = nil // mangerperipheral } func pairFail() { print("pairFail") disconnect() // peripheral = nil // manger.peripheral = nil manger?.foundPeripherals = nil manger?.tempPeripheral = nil manger?.connectedService = nil manger?.connectPeripherals = nil // if centralManger != nil { // if centralManger!.isScanning { // centralManger?.stopScan() // } // centralManger = nil // } connectedPerArray = [] } //MARK: - 设置 func getSettingData(completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getSettingCmd() self.setDataClosure = completion // print("??? --- \(setCmdClosure)") sendData(data) } func setUserInfo(_ user: UserInfoModel, completion: ((_ error: Int?) -> ())? = nil) { // let data = BleMessage.shared.getUserCmd(user) // self.setCmdClosure = completion // sendData(data) newSetUserInfo(user, completion: completion) } func setLanguage(_ language: AppSettings.Language, timeFormat: TimeFormat, screenOnTime: Int, pair: UInt8, completion: ((_ error: Int?) -> ())? = nil) { let lan: UInt8 = language == .Chinese ? 0x00 : 0x01 newSetLanguage(lan: lan, completion: completion) } func setTime(format: TimeFormat, completion: ((_ error: Int?) -> ())? = nil) { newSetTime(completion: completion) } func setWeather(_ array: [WeatherModel], completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getWeatherCmd(array) self.setCmdClosure = completion sendData(data) } func syncContacts(_ array: [ContactModel], progress: @escaping ContactProgressClosure, completion: ((_ error: Int?) -> ())? = nil) { contactArray = array // let data = BleMessage.shared.getSyncContactsCmd(array, num: num) contactProgressClosure = progress self.setCmdClosure = completion print("同步联系人1-2") syncSubContacts(Array(array[0...1]), num: 1) // sendData(data) } func syncSubContacts(_ array: [ContactModel], num: Int) { let data = BleMessage.shared.getSyncContactsCmd(array, num: num) sendData(data) } func setCard(_ string: String, type: Int, completion: @escaping(_ error: Int?) -> ()) { let data = BleMessage.shared.getCardCmd(string, type: type) self.setCmdClosure = completion sendData(data) } func setPay(_ string: String, type: Int, completion: @escaping(_ error: Int?) -> ()) { let data = BleMessage.shared.getPayCmd(string, type: type) self.setCmdClosure = completion sendData(data) } func setMessagePush(_ push: MessagePushModel, completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getMessagePush(push) self.setCmdClosure = completion sendData(data) } func setAlarmClock(_ array: [AlarmClockModel], completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getAlarmClockCmd(array) self.setCmdClosure = completion sendData(data) } func setDrinkWaterRemind(_ remind: RemindModel, completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getDrinkWaterCmd(remind) self.setCmdClosure = completion sendData(data) } func setSedentaryRemind(_ remind: RemindModel, completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getSedentaryCmd(remind) self.setCmdClosure = completion sendData(data) } func setNotDisturb(remind: RemindModel, completion: @escaping(_ error: Int?) -> ()) { newSetNotDisturb(remind: remind, weekflag: [.sunday, .friday], isRepeat: true, completion: completion) } func setWristSense(_ bool: Bool, completion: ((_ error: Int?) -> ())? = nil) { newSetWristSense(bool: bool, completion: completion) } func setAutoMeasure(_ bool: Bool, completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getAutoMeasureCmd(bool) self.setCmdClosure = completion sendData(data) } func setMenstrual(_ menstrual: MenstrualCalendarModel, completion: ((_ error: Int?) -> ())? = nil) { let data = BleMessage.shared.getMenstrualCmd(menstrual) self.setCmdClosure = completion sendData(data) } func syncLanguage() { let lan: UInt8 = AppSettings.shared.language == .Chinese ? 0x00 : 0x01 newSetLanguage(lan: lan) } func syncBase(language: AppSettings.Language, timeFormat: TimeFormat) { } func syncTime(format: TimeFormat) { let data = BleMessage.shared.getTimeCmd() sendData(data) } func openCamera(_ status: Bool) { let data = BleMessage.shared.getCameraCmd(status) sendData(data) } func findDevice(_ status: Bool) { switch platform { case ._828: if status { let data = BleMessage.shared.getFindCmd(status) sendData(data) } case .other: break } } func queryBattery() { let data = BleMessage.shared.getBatteryCmd() sendData(data) } //MARK: - 表盘, 固件升级 func getFirmwareVersion(isAlert: Bool = true, closure: @escaping(_ version: String, _ type: String, _ updateDic: [String: String], _ error: Int?) -> ()) { firmwareCallbackClosure = closure firmwareAlert = isAlert let data = BleMessage.shared.getFirmwareCmd() sendData(data) } var OTAProfile: RTKOTAProfile? = nil var OTAPeripheral: RTKOTAPeripheral? = nil var DFUPeripheral: RTKMultiDFUPeripheral? = nil var upgradeBins: [RTKOTAUpgradeBin] = [] var isFirmwareUpdate: Bool = false func syncFileWith(path: String, isFirmware: Bool = false, progress: @escaping SyncRTKProgressClosure, completion: @escaping SyncRTKClosure) { isFirmwareUpdate = isFirmware if OTAPeripheral == nil { return } startSyncDial() syncRTKProgressClosure = progress syncRTKClosure = completion do { upgradeBins = try RTKOTAUpgradeBin.imagesExtracted(fromMPPackFilePath: path) } catch { print("fail") return } if upgradeBins.count == 1 { if !(upgradeBins.last!.icDetermined) { upgradeBins.last?.assertAvailable(for: OTAPeripheral!) } } if OTAPeripheral!.canUpgradeSliently && !OTAPeripheral!.isRWS { let peripheral = OTAProfile!.dfuPeripheral(of: OTAPeripheral!) DFUPeripheral = peripheral as? RTKMultiDFUPeripheral DFUPeripheral!.delegate = self OTAProfile?.connect(to: DFUPeripheral!) } } func toUpgradeImages() -> [RTKOTAUpgradeBin] { if OTAPeripheral == nil { return [] } switch OTAPeripheral?.activeBank.rawValue { case 0: let imagesForBank1: [RTKOTAUpgradeBin] = self.upgradeBins.filter{$0.upgradeBank == .bank1} if imagesForBank1.count > 0 { return [] } else { return self.upgradeBins } case 1: return self.upgradeBins.filter{$0.upgradeBank == .bank1 || $0.upgradeBank == .unknown} case 2: return self.upgradeBins.filter{$0.upgradeBank == .singleOrBank0 || $0.upgradeBank == .unknown} default: return self.upgradeBins } } var syncDialIndex: Int = 0 var dialLength: Int = 0 var dialFileContents: [String] = [] var dialDirectoryPath: String = "" // var dialRemainData: Data = Data() func syncDialWith(path: String, progress: @escaping DialProgressClosure, completion: @escaping DialClosure) { guard let contentsOfPath = try? FileManager.default.contentsOfDirectory(atPath: path), contentsOfPath.count > 0 else { return } dialDirectoryPath = path dialFileContents = contentsOfPath dialProgressClosure = progress dialClosure = completion dialLength = contentsOfPath.count syncDialIndex = 0 sendDialData(BleMessage.shared.getSyncDialCmd(bytes: [0x02])) } func sendNextSyncData() { if syncDialIndex < dialLength { guard var dataStr = try? String.init(contentsOfFile: "\(dialDirectoryPath)/\(dialFileContents[syncDialIndex])", encoding: .utf8), dataStr.count > 0 else { return } dataStr = dataStr.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "") sendDialData(BleMessage.shared.getSyncDialCmd(bytes: dataStr.hexaBytes)) if dialProgressClosure != nil { dialProgressClosure?(Int(Float(syncDialIndex)/Float(dialLength)*100)) } } else if syncDialIndex == dialLength { if dialProgressClosure != nil { dialProgressClosure?(100) } sendDialData(BleMessage.shared.getSyncDialCmd(bytes: [0x03])) if dialClosure != nil { dialClosure?(nil) } } else { return } syncDialIndex += 1 } // var syncDialIndex: Int = 0 // var dialLength: Int = 0 var customDialData: Data = Data() var isSyncDial: Bool = false // var dialDirectoryPath: String = "" func syncCustomDial(_ data: Data, colorStyle: Int = 0, position: Int = 0, progress: @escaping CustomDialProgressClosure, completion: @escaping CustomDialClosure) { if data.count < 54 { return } customProgressClosure = progress customClosure = completion // let headerBytes = Array([UInt8](data)[0..<54]) customDialData = data//Data(bytes: Array([UInt8](data)[54.. 0 { print(StepModel.toStepModel(bytes)) StepModel.toStepModel(bytes).realTimeAdd() for delegate in syncDelegateList { delegate.didReceiveStep() } } } func parseRealTimeBloodOxygen(_ bytes: [UInt8]) { if bytes.count == 1 { BloodOxygenModel(value: Int(bytes[0]), date: DateInRegion().date).realTimeAdd() for delegate in syncDelegateList { delegate.didReceiveBloodOxygen() } } } func parseRealTimeBloodPressure(_ bytes: [UInt8]) { if bytes.count == 2 { BloodPressureModel(dbp: Int(bytes[1]), sbp: Int(bytes[0]), date: DateInRegion().date).realTimeAdd() for delegate in syncDelegateList { delegate.didReceiveBloodPressure() } } } func parseRealTimeHeartRate(_ bytes: [UInt8]) { if bytes.count == 1 { HeartRateModel(value: Int(bytes[0]), date: DateInRegion().date).realTimeAdd() for delegate in syncDelegateList { delegate.didReceiveHeartRate(value: Int(bytes[0])) } } } private func parseSyncData(_ key: SyncCmd?, bytes: [UInt8]) { stopSyncTimer(BLEConfig.SyncHealthTimer) if !isNextSync { isSync = false isSyncType = .other } switch key { case .sleep: parseHistorySleep(bytes) case .hr: parseHistoryHeartRate(bytes) case .bp: parseHistoryBloodPressure(bytes) case .bo: parseHistoryBloodOxygen(bytes) case .step: parseHistoryStep(bytes) case .train: parseHistoryTrain(bytes) case .pressure: parseHistoryPressure(bytes) case .mett: parseHistoryMett(bytes) case .bo_rt: parseRealTimeBloodOxygen(bytes) case .bp_rt: parseRealTimeBloodPressure(bytes) case .hr_rt: parseRealTimeHeartRate(bytes) case .step_rt: parseRealTimeSteps(bytes) default: break } } private func parseSettingData(_ data: Data) { let bytes = Array([UInt8](data)[13.. 75 { admin.userInfo.isDailSync = Int(bytes[74]) == 1 admin.userInfo.timeFormat = Int(bytes[76]) } //74表盘 //75语言 //76时间格式 // 1, 24, 175, 65, 16, 39, // 1, 24, 175, 65, 16, 39, 0, AdminHelper.shared.savaAdminInfo(admin) for delegate in syncDelegateList { delegate.didReceiveSettingData() } } private func parseDeviceData() { } private func parseSetData(_ key: SetCmd?, data: Data) { // print("\(key) --- \(setCmdClosure)") switch key { case .firmware: print("!!firmware!!!!\([UInt8](data))") case .firmware_return: let version = "\([UInt8](data)[13]).\([UInt8](data)[14]).\([UInt8](data)[15])" let type = String(format:"%04d",[UInt8](data)[19]) let device = CurDevice device.version = version device.type = type AdminHelper.shared.updateDevice(device) queryLatestVersion(version: version, type: type) print("!!firmware!!!!\([UInt8](data))") case .alarmClock: if isManagerSync { isManagerSync = false self.syncDrinkRemind() } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } print("!!alarmClock!!!!\([UInt8](data))") case .set_return: parseSettingData(data) if setDataClosure != nil { setDataClosure?(nil) setDataClosure = nil } print("!!!!!!!\([UInt8](data))") case .wrist://用户信息 --- 单位 --- 抬腕亮屏 --- 整点测量 --- 闹钟 --- 喝水 --- 久坐 if isManagerSync { isManagerSync = false self.syncAutoMeasure() } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .autoMeasure: if isManagerSync { isManagerSync = false self.syncAlarmClocks() } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .user: if isManagerSync { isManagerSync = false if CurDevice.name.contains("P8GT") { self.syncDeivceLanguage() } else { self.syncUnit() } } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .unit: if isManagerSync { isManagerSync = false self.syncWristSense() } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .push: if isManagerSync { isManagerSync = false self.setMenstrualStatus() } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .menstrual: if isManagerSync { isManagerSync = false self.firstSyncDone() } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .time: if isManagerSync { isManagerSync = false self.syncMessagePush() // self.setMenstrualStatus() } if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .setting: print("!!setting!!!!\([UInt8](data))") case .card, .pay: if setCmdClosure != nil { setCmdClosure?(nil) setCmdClosure = nil } case .custom: if !isSyncDial { return } syncDialIndex += 1 startSyncDial() // print("\(syncDialIndex) ---- \(dialLength)") if syncDialIndex == dialLength { isSyncDial = false if GCDTimer.shared.isExistTimer(WithTimerName: "SyncDial") { GCDTimer.shared.cancleTimer(WithTimerName: "SyncDial") } if customClosure != nil { customClosure?(nil) } } else if syncDialIndex < dialLength { let i = syncDialIndex-1 print("\(i)==\(customDialData.count)") sendCustomDialData(customDialData[i*240.. Void in let mySelf = Unmanaged.fromOpaque(inClientData!).takeUnretainedValue() mySelf.audioServicesPlaySystemSoundCompleted(soundID: soundID) }, observer) AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) case .find_phone_stop: self.audioPlayer.stop() AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate) AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate) case .find_device: for delegate in syncDelegateList { delegate.didReceiveFindPhoneCommand(value: 1) } case .sync: print("同步") case .weather: print("同步天气????????") case .none: print("") case .dial: print("") case .battery_return: if GCDTimer.shared.isExistTimer(WithTimerName: "queryBattary") { GCDTimer.shared.cancleTimer(WithTimerName: "queryBattary") } if data.count > 13 { Battery = Int([UInt8](data)[13]) var isCharging = false if data.count > 14 { isCharging = [UInt8](data)[14] == 2 } for delegate in syncDelegateList { delegate.didReceiveBattery(value: Battery) } } } } //音频结束时的回调 func audioServicesPlaySystemSoundCompleted(soundID: SystemSoundID) { print("Completion") AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) } private func sendCustomDialData(_ data: Data) { if !isSyncDial { return } if peripheral == nil || data.count == 0 { return } // print("\(data.count)----\([UInt8](data))") if let services = peripheral?.services { for service in services { if service.uuid.uuidString == BLEConfig.ServerUUID { if service.characteristics == nil { return } for char in service.characteristics! { if char.uuid.uuidString == BLEConfig.WriteUUID { // print("自定义表盘发送: \([UInt8](data))") peripheral?.writeValue(data, for: char, type: .withResponse) } } } } } } private func sendDialData(_ data: Data) { if peripheral == nil || data.count == 0 { return } if let services = peripheral?.services { for service in services { if service.uuid.uuidString == BLEConfig.MTKDialServerUUID { if service.characteristics == nil { return } for char in service.characteristics! { if char.uuid.uuidString == BLEConfig.MTKDialWriteUUID { if data.count <= 180 { print([UInt8](data)) peripheral?.writeValue(data, for: char, type: .withResponse) } else { let n = data.count/180 + (data.count%180 == 0 ? 0 : 1) for i in 0..= 0 else { return } switch characteristic.uuid.uuidString { case BLEConfig.MTKBasReadUUID: print("电量------\([UInt8](data))") Battery = Int([UInt8](data)[0]) for delegate in syncDelegateList { delegate.didReceiveBattery(value: Battery) } case BLEConfig.MTKDialReadUUID: print("表盘------\([UInt8](data))") let bytes = [UInt8](data) if bytes.count > 13 { if bytes[13] == 1 { sendNextSyncData() } else if bytes[13] == 2 { // sendDialData(dialRemainData) } } case BLEConfig.ReadUUID: print("接收: \([UInt8](data))") mergeData(data) default: print("接收: \([UInt8](data))") mergeData(data) } } func mergeData(_ data: Data) { let bytes = [UInt8](data) // print(bytes) isSyncReceived = true if bytes[0] == 0xED && bytes[1] == 0x7E { // if bytes.count > 10, BleCmd(rawValue: bytes[8]) == .sync { // if isSync { // if SyncCmd(rawValue: bytes[10]) != isSyncType { // syncReceiveFail() // } else { // isNextSync = bytes[1] == 112 // startSyncTimer() // isSyncReceived = true // } // } // } // 内容长度加上其他位的长度 totalLength = Int(UInt16(bytes[8]) << 8 | UInt16(bytes[9])) + 12 if data.count == totalLength { parseData(bytes) } else { totalBytes = [] totalBytes.append(contentsOf: bytes) mergeLength = bytes.count } } else { if isSync { if isSyncReceived { startSyncTimer() isSyncReceived = true } } totalBytes.append(contentsOf: bytes) mergeLength += bytes.count if mergeLength == totalLength { parseData(totalBytes) } } } func onCharacteristicWrite() { // print("已经连接5") } func onReadRssi(_ peripheral: CBPeripheral!, rssiValue rssi: Int32, error err: Error!) { // print("已经连接6") } } extension BluetoothManager: CBCentralManagerDelegate { func centralManagerDidUpdateState(_ central: CBCentralManager) { switch central.state { case .unknown: print("unknown1") case .resetting: print("resetting1") case .unsupported: print("unsupported1") case .unauthorized: if let curVC = UIViewController.getCurrentViewController() { curVC.showAlert(title: LocString("提示"), message: LocString("请在“设置-隐私-蓝牙”选项中,允许'YTWatch'使用蓝牙"), cancelText: nil, confirm: nil) } print("unauthorized1") case .poweredOff: print("poweredOff1") case .poweredOn: print("poweredOn1") centralManger?.scanForPeripherals(withServices: nil, options: nil) @unknown default: print(" ") } for delegate in delegateList { delegate.centralManagerDidUpdateState(central.state.rawValue) } } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { print("jason_bluetooth_action_1:通过CBCentralManagerDelegate回调得到扫描结果"); print("jason " + (peripheral.name ?? "")); if peripheralDic.keys.contains(peripheral.identifier.uuidString) { return } // if peripheral.name?.range(of: "You 1_LE") != nil || peripheral.name?.range(of: "Pro_LE") != nil || peripheral.name?.range(of: "MTB025B") != nil || peripheral.name?.range(of: "MTB033B") != nil || peripheral.name?.range(of: "hq7") != nil || peripheral.name?.range(of: "D09") != nil || peripheral.name?.range(of: "P8GT") != nil || peripheral.name?.range(of: "hq8") != nil || peripheral.name?.range(of: "Watch 8") != nil || peripheral.name?.range(of: "D07") != nil || peripheral.name?.range(of: "S7 NO.1") != nil || peripheral.name?.range(of: "G7 Pro Max Gameboy") != nil { if peripheral.name?.range(of: "KV-S10f44efd8deb8b") != nil { peripheralDic[peripheral.identifier.uuidString] = peripheral // print(peripheral.name)key String "kCBAdvDataServiceData" if let data = advertisementData["kCBAdvDataManufacturerData"] as? Data { var mac = data.hexToString(":") mac = mac.substring(fromIndex: mac.length-17) deviceArray.append(ScanDevice(peripheral, mac: mac)) for delegate in delegateList { delegate.didDiscover(devices: deviceArray) } } else { // 该设备无值 // if let json = advertisementData["kCBAdvDataServiceData"] { // if let dic = json as? Dictionary { // if let data = dic.values.first { // var mac = data.hexToString(":") // mac = mac.substring(fromIndex: mac.length-17) deviceArray.append(ScanDevice(peripheral, mac: "111")) for delegate in delegateList { delegate.didDiscover(devices: deviceArray) } // } // } // } } } } } extension BluetoothManager: RTKMultiDFUPeripheralDelegate, RTKLEProfileDelegate { func profileManagerDidUpdateState(_ profile: RTKLEProfile) { if profile.centralManager.state == .poweredOn && self.peripheral != nil { // print("RTK??????????????") OTAPeripheral = OTAProfile?.instantiatePeripheral(with: self.peripheral!) as? RTKOTAPeripheral OTAProfile?.connect(to: OTAPeripheral!) } } func dfuPeripheral(_ peripheral: RTKDFUPeripheral, didSend length: UInt, totalToSend totalLength: UInt) { print("\(length) ---- \(totalLength)") startSyncDial() syncRTKProgressClosure?(Int(Float(length)/Float(totalLength)*100)) } func profile(_ profile: RTKLEProfile, didConnect peripheral: RTKLEPeripheral) { if peripheral == self.DFUPeripheral { DFUPeripheral?.upgradeImages(self.toUpgradeImages(), inOTAMode: false) } } func dfuPeripheral(_ peripheral: RTKDFUPeripheral, didFinishWithError err: Error?) { // if err != nil { print("dfuPeripheral \\ \(err)") isSyncDial = false if GCDTimer.shared.isExistTimer(WithTimerName: "SyncDial") { GCDTimer.shared.cancleTimer(WithTimerName: "SyncDial") } syncRTKClosure?(err) // } } func dfuPeripheral(_ peripheral: RTKDFUPeripheral, shouldWaitForDisconnectionOnCompleteSend image: RTKOTAUpgradeBin) -> Bool { return isFirmwareUpdate } } extension BluetoothManager: XMLParserDelegate { private func queryLatestVersion(version: String, type: String) { Alamofire.request("http://hodafone.com.cn/qwear/update/\(type)/version.xml").responseData { responseData in if responseData.response?.statusCode == 404 { self.firmwareCallbackClosure?(version, type, [:], nil) } else { if let data = responseData.data { let parser = XMLParser(data: data) parser.delegate = self parser.parse() } } } } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { let device = CurDevice if elementName == "product" { if let least = attributeDict["least"], let file = attributeDict["file"], let id = attributeDict["id"] { if CurDevice.version.checkVersion(least) { print("需要升级") firmwareCallbackClosure?(device.version, device.type, ["least": least, "file": file, "id": id], nil) if let curVC = UIViewController.getCurrentViewController(), !(curVC is FirmwareUpdateVC) { // print(NSStringFromClass(type(of: curVC))) if firmwareAlert { if firmwareAlertView == nil { firmwareAlertView = FirmwareRemindView(title: LocString("版本更新"), detail: LocString("监测到你的手表当前使用的不是最新版本固件,为了不影响手表的正常使用,并给你带来更好的用户体验,请务必将手表更新至最新固件版本。"), sureText: LocString("去更新")) self.firmwareAlertView?.show() self.firmwareAlertView?.clickClosure = {[weak self] index in self?.firmwareAlertView = nil let vc = UIStoryboard.loadViewControllerIdentifier(storyboardName: "Setting", identifier: "FirmwareUpdateVC") curVC.navigationController?.pushViewController(vc, animated: true) } } } } } else { firmwareCallbackClosure?(device.version, device.type, [:], nil) } } } // func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { // if elementName == "product"{ // print(attributeDict) // if let least = attributeDict["least"] { // latestVersion = least // checkUpdate() // } // if let file = attributeDict["file"] { // downLoadUrlPath = file // } // if let id = attributeDict["id"] { // self.id = id // } // // } // } } } extension BluetoothManager { private func startSync828(_ delayTime: Double) { self.syncBug() isFirstSync = true GCDTimer.shared.scheduledDispatchTimerNotNow(WithTimerName: "SyncTime", timeInterval: delayTime, queue: .main, repeats: false) { self.syncUserInfo() } // GCDTimer.shared.scheduledDispatchTimerNotNow(WithTimerName: "SyncTime", timeInterval: delayTime, queue: .main, repeats: false) { // self.syncDeviceTime() // } } //828: 用户信息 --- 单位 --- 抬腕亮屏 --- 整点测量 --- 闹钟 --- 喝水 --- 久坐 --- 时间 --- 消息通知 --- 月经 //P8GT 用户信息 --- 语言 --- 单位 --- 抬腕亮屏 --- 整点测量 --- 闹钟 --- 喝水 --- 久坐 --- 时间 --- 消息通知 --- 月经 func syncUserInfo() { print("用户信息") let user = UserInfo self.setUserInfo(user, completion: nil) self.isManagerSync = true } func syncUnit() { print("同步单位") let user = UserInfo newSetDistanceUnit(unit:DistanceUnit(rawValue: UInt8(user.distanceUnit))!) { [weak self] error in if error == nil { self?.newSetTemperatureUnit(unit: TemperatureUnit(rawValue: UInt8(user.temperatureUnit))!) { error in } } } self.isManagerSync = true } func syncWristSense() { print("同步抬腕亮屏") let user = UserInfo self.setWristSense(user.wrist, completion: nil) self.isManagerSync = true } func syncAutoMeasure() { print("同步整点测量") let user = UserInfo self.setAutoMeasure(user.autoMasure, completion: nil) self.isManagerSync = true } func syncAlarmClocks() { print("同步闹钟") let user = UserInfo self.setAlarmClock(user.alarmClocks, completion: nil) self.isManagerSync = true } func syncDrinkRemind() { print("同步喝水") let user = UserInfo self.setDrinkWaterRemind(user.drink, completion: nil) self.isManagerSync = true } func syncSedentaryRemind() { print("同步久坐") let user = UserInfo self.setSedentaryRemind(user.sedentary, completion: nil) self.isManagerSync = true } func syncDeviceTime() { print("同步时间") let user = UserInfo self.setTime(format: TimeFormat(rawValue: UInt8(user.timeFormat))!, completion: nil) self.isManagerSync = true } func syncDeivceLanguage() { let admin = AdminHelper.shared.loadLocalAdminData() print("同步语言") let curLanguage = AppSettings.Language(rawValue: admin.device.languageRaw)! self.setLanguage(curLanguage, timeFormat: TimeFormat(rawValue: UInt8(admin.userInfo.timeFormat))!, screenOnTime: 5, pair: 0, completion: nil) self.isManagerSync = true } func syncMessagePush() { let user = UserInfo print("同步消息推送") BluetoothManager.shared.setMessagePush(user.push, completion: nil) self.isManagerSync = true } func setMenstrualStatus() { print("同步月经") // print(MenstrualCalendarModel.getAllDate()) let menstrual = MenstrualCalendarModel.getAllDate() let selectedDate = DateInRegion().date.dateAtStartOf(.day) let menstrualModel: MenstrualModel = UserInfo.menstrual if menstrual.count > 0 { if let model = MenstrualCalendarModel.getDate(DateInRegion().date.dateAtStartOf(.day)) { self.setMenstrual(model, completion: nil) self.isManagerSync = true } else { let n: Int = (selectedDate - MenstrualCalendarModel.getLastMenstrual()!.date!.dateAtStartOf(.day)).in(.day) ?? 0 for i in 0..