From 3de8b1d5554503ebe9a08ba399e6507a2ae99792 Mon Sep 17 00:00:00 2001 From: lishuo Date: Tue, 24 Aug 2021 18:34:41 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E8=93=9D=E7=89=99?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=AD=A3=E5=B8=B8=E9=AA=91=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Android/unityandroidbluetoothlelib.jar | Bin 31910 -> 36890 bytes Assets/Plugins/BluetoothDeviceScript.cs | 37 +- Assets/Plugins/BluetoothHardwareInterface.cs | 5 +- Assets/Scripts/Devices/Ble/BleDevice.cs | 2 +- .../Devices/Ble/mobile/BleMobileInterface.cs | 414 ++++++------------ .../Devices/Ble/mobile/BleMobileThread.cs | 116 ++--- .../Scenes/Ride/Scripts/PlayerController.cs | 2 +- 7 files changed, 226 insertions(+), 350 deletions(-) diff --git a/Assets/Plugins/Android/unityandroidbluetoothlelib.jar b/Assets/Plugins/Android/unityandroidbluetoothlelib.jar index 437b1c9886048332b03d04a98f9f88cb580a0fa3..588e16217adb295a08e4385a7310328a3e2c9160 100644 GIT binary patch literal 36890 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Μc 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 diff --git a/Assets/Plugins/BluetoothDeviceScript.cs b/Assets/Plugins/BluetoothDeviceScript.cs index f056aeed..102148b9 100644 --- a/Assets/Plugins/BluetoothDeviceScript.cs +++ b/Assets/Plugins/BluetoothDeviceScript.cs @@ -10,14 +10,15 @@ public class BluetoothDeviceScript : MonoBehaviour public List DiscoveredDeviceList; - public Action InitializedAction; + public Action InitializedAction { get; set; } public Action DeinitializedAction; public Action ErrorAction; public Action ServiceAddedAction; + public Action BleStatusChangedAction; public Action StartedAdvertisingAction; public Action StoppedAdvertisingAction; public Action DiscoveredPeripheralAction; - public Action DiscoveredPeripheralWithAdvertisingInfoAction; + public Action DiscoveredPeripheralWithAdvertisingInfoAction; public Action DiscoveredBeaconAction; public Action RetrievedConnectedPeripheralAction; public Action PeripheralReceivedWriteDataAction; @@ -71,6 +72,7 @@ public class BluetoothDeviceScript : MonoBehaviour const string deviceDidUpdateValueForCharacteristic = "DidUpdateValueForCharacteristic"; const string deviceLog = "Log"; const string deviceRequestMtu = "MtuChanged"; + const string bleStatusChanged = "BleStatusChanged"; public void OnBluetoothMessage (string message) { @@ -78,7 +80,17 @@ public class BluetoothDeviceScript : MonoBehaviour { char[] delim = new char[] { '~' }; string[] parts = message.Split (delim); - + if (parts[0].Equals("DeviceStateChanged")) + { + //throw new Exception("test"); + } + if (parts[0].Equals(bleStatusChanged)) + { + if (BleStatusChangedAction != null) + { + BleStatusChangedAction(int.Parse(parts[1])); + } + } for (int i = 0; i < parts.Length; ++i) BluetoothLEHardwareInterface.Log(string.Format("Part: {0} - {1}", i, parts[i])); @@ -152,11 +164,22 @@ public class BluetoothDeviceScript : MonoBehaviour int rssi = 0; if (!int.TryParse (parts[3], out rssi)) rssi = 0; + List uuidList = new List(); + if (parts[4].Contains(",")) + { + string[] s = parts[4].Split(','); + foreach (var o in s) + { + if (!string.IsNullOrEmpty(o)) + { + uuidList.Add(o); + } + } + } + //// parse the base 64 encoded data that is the 5th value + //byte[] bytes = System.Convert.FromBase64String (parts[4]); - // parse the base 64 encoded data that is the 5th value - byte[] bytes = System.Convert.FromBase64String (parts[4]); - - DiscoveredPeripheralWithAdvertisingInfoAction (parts[1], parts[2], rssi, bytes); + DiscoveredPeripheralWithAdvertisingInfoAction (parts[1], parts[2], rssi, uuidList.ToArray()); } } } diff --git a/Assets/Plugins/BluetoothHardwareInterface.cs b/Assets/Plugins/BluetoothHardwareInterface.cs index b7c11ed1..4c80d913 100644 --- a/Assets/Plugins/BluetoothHardwareInterface.cs +++ b/Assets/Plugins/BluetoothHardwareInterface.cs @@ -266,7 +266,7 @@ public class BluetoothLEHardwareInterface #endif } - public static BluetoothDeviceScript Initialize (bool asCentral, bool asPeripheral, Action action, Action errorAction) + public static BluetoothDeviceScript Initialize (bool asCentral, bool asPeripheral, Action action, Action errorAction, Action statusAction) { bluetoothDeviceScript = null; @@ -289,6 +289,7 @@ public class BluetoothLEHardwareInterface if (bluetoothDeviceScript != null) { + bluetoothDeviceScript.BleStatusChangedAction = statusAction; bluetoothDeviceScript.InitializedAction = action; bluetoothDeviceScript.ErrorAction = errorAction; } @@ -475,7 +476,7 @@ public class BluetoothLEHardwareInterface #endif } - public static void ScanForPeripheralsWithServices (string[] serviceUUIDs, Action action = null, Action actionAdvertisingInfo = null, bool rssiOnly = false, bool clearPeripheralList = true, int recordType = 0xFF) + public static void ScanForPeripheralsWithServices (string[] serviceUUIDs, Action action = null, Action actionAdvertisingInfo = null, bool rssiOnly = false, bool clearPeripheralList = true, int recordType = 0xFF) { #if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR if (!Application.isEditor) diff --git a/Assets/Scripts/Devices/Ble/BleDevice.cs b/Assets/Scripts/Devices/Ble/BleDevice.cs index 5b799534..beadb367 100644 --- a/Assets/Scripts/Devices/Ble/BleDevice.cs +++ b/Assets/Scripts/Devices/Ble/BleDevice.cs @@ -123,7 +123,7 @@ namespace Assets.Scripts.Devices.Ble Debug.Log("断开设备" + this.Name); //App.MainDeviceAdapter.PrintStatus(); - + this.State = DeviceState.Disconnected; this.hwInterface.DisconnectPeripheral(this.peripheralInfo, () => { //App.MainDeviceAdapter.PrintStatus(); diff --git a/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs b/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs index 2d45a78a..b18fa19f 100644 --- a/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs +++ b/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs @@ -13,7 +13,7 @@ using UnityEngine; namespace Assets.Scripts.Ble { - public sealed class BleMobileInterface: IBleWinHwInterface + public sealed class BleMobileInterface : IBleWinHwInterface { private static BleMobileInterface hwInterface; private BleMobileThread bleMobileThread; @@ -68,7 +68,7 @@ namespace Assets.Scripts.Ble this.bluetoothStateChanged -= value; } } - + private BleState nativeState; public BleState BleState { @@ -78,7 +78,7 @@ namespace Assets.Scripts.Ble } set { - if(this.nativeState != value) + if (this.nativeState != value) { this.nativeState = value; this.bluetoothStateChanged?.Invoke(this, this.nativeState); @@ -102,58 +102,61 @@ namespace Assets.Scripts.Ble private BleMobileInterface() { bleMobileThread = new BleMobileThread(); + bleMobileThread.ManagerInitialized += BleMobileThread_ManagerInitialized; + bleMobileThread.ManagerStatusChanged += ManagerStatusChanged; bleMobileThread.ScanInfoReceived += WatcherScanInfoReceived; } - private void WatcherScanInfoReceived(BleMobileThread sender, string address, string name, int rssi,string type) + private void BleMobileThread_ManagerInitialized(BleMobileThread thread) { - //if (address != 224160707349234) - //{ - // return; - //} + this.BleState = BleState.On; + } + private void ManagerStatusChanged(BleMobileThread sender, WclBleManagerStatus status) + { + this.BleState = BleMobileInterface.StateFromNativeState(status); + } + + private void WatcherScanInfoReceived(BleMobileThread sender, string address, string name, int rssi,string[] uuids) + { SensorType sensor = SensorType.None; List services = new List(); - if (type.Equals("trainer")) + + if (uuids != null && uuids.Length > 0) { - sensor = SensorType.Trainer; - } - else - { - sensor = SensorType.HeartRate; - } - //if (service != null) - //{ - // services = new List { service.Value }; - // foreach (var item in ServiceUuids.Services) - // { - // if (item.IdGuid != service.Value) - // { - // continue; - // } - // if (item.IdByteArray == ServiceUuids.Ftms) - // { - // sensor = SensorType.Trainer; - // } - // else if (item.IdByteArray == ServiceUuids.HeartRate) - // { - // sensor = SensorType.HeartRate; - // } - // else if (item.IdByteArray == ServiceUuids.CyclingPower) - // { - // sensor = SensorType.Power; - // //sensor = SensorType.Trainer; - // } - // else if (item.IdByteArray == ServiceUuids.CyclingSpeedCadence) - // { - // sensor = SensorType.SpeedCadence; - // } - // else if (item.IdByteArray == ServiceUuids.TacxBle) - // { - // sensor = SensorType.Trainer; - // } - // } - //}; + foreach (var item in uuids) + { + services.Add(new Guid(item)); + } + foreach (var item in ServiceUuids.Services) + { + if (!uuids.Contains(item.IdGuid.ToString())) + { + continue; + } + if (item.IdByteArray == ServiceUuids.Ftms) + { + sensor = SensorType.Trainer; + } + else if (item.IdByteArray == ServiceUuids.HeartRate) + { + sensor = SensorType.HeartRate; + } + else if (item.IdByteArray == ServiceUuids.CyclingPower) + { + sensor = SensorType.Power; + //sensor = SensorType.Trainer; + } + else if (item.IdByteArray == ServiceUuids.CyclingSpeedCadence) + { + sensor = SensorType.SpeedCadence; + } + else if (item.IdByteArray == ServiceUuids.TacxBle) + { + sensor = SensorType.Trainer; + } + } + }; var addressStr = address; if (!pCache.ContainsKey(addressStr)) @@ -174,10 +177,10 @@ namespace Assets.Scripts.Ble //Debug.Log(sensor); //pCache[address.ToString()].SensorType = sensor; - //foreach (var item in services) - //{ - // pCache[addressStr].TryAddService(item); - //} + foreach (var item in uuids) + { + pCache[addressStr].TryAddService(new Guid(item)); + } pCache[addressStr].Index++; if (pCache[addressStr].SensorType == SensorType.Power && pCache[addressStr].Services.Any(s => s.Equals(ServiceUuids.Get(ServiceUuids.TacxBle).IdGuid))) @@ -198,7 +201,6 @@ namespace Assets.Scripts.Ble { _discoveredCallback?.Invoke(pCache[addressStr]); } - this.BleState = BleState.On; } //private WclBleGattThread SetUpGattClient(BlePeripheralInfo peripheral) @@ -220,21 +222,6 @@ namespace Assets.Scripts.Ble List characteristilist = new List(); public void ConnectPeripheral(BlePeripheralInfo info, Action callback) { - //this.callbacks.Add(info, callback); - //WclBleGattThread wclBleGattThread = this.wclBleMainThread.GetGattThread(info); - - //if (wclBleGattThread == null) - //{ - - // wclBleGattThread = this.SetUpGattClient(info); - // this.ConnectInternal(wclBleGattThread); - // return; - //} - //else - //{ - // this.ConnectInternal(wclBleGattThread); - //}\ - BleResponse s = new BleResponse(); s.IsSuccess = true; s.Error = null; @@ -243,48 +230,49 @@ namespace Assets.Scripts.Ble { callback?.Invoke(self, info, s); }, (address, service) => { - var l = servicelist.Where(c => c.Id.ToString().Equals(service)).ToList(); - if (l.Count == 0) + if (servicesCallbacks.Where(c => c.Key.Address == address).Any()) { - servicelist.Add(new WinBleServiceInfo(info,new Guid(service))); - } - }, (address, service, characteristic) => - { - var l = characteristilist.Where(c => c.Id.ToString().Equals(characteristic)).ToList(); - if (l.Count == 0) - { - //characteristilist.Add(new BleCharacteristicInfo new WinBleServiceInfo(info, new Guid(characteristic))); + + var serviceCallback = servicesCallbacks.Where(c => c.Key.Address == address).FirstOrDefault(); + List servicelist = new List(); + servicelist.Add(new WinBleServiceInfo(serviceCallback.Key,new Guid(service))); + BleResponse> response = new BleResponse> + { + IsSuccess = true, + Error = null, + Data = servicelist, + }; + serviceCallback.Value?.Invoke(this, serviceCallback.Key, response); } + }, (address, service, characteristic) => + { + if (characteristicsDiscoveredCallbacks.Where(c => c.Key.Peripheral.Address == address).Any()) + { + var characteristicCallback = characteristicsDiscoveredCallbacks.Where(c => c.Key.Peripheral.Address == address).FirstOrDefault(); + List characteristiclist = new List(); + characteristiclist.Add(new WinBleCharacteristicInfo(new Guid(characteristic), new WinBleServiceInfo(characteristicCallback.Key.Peripheral, new Guid(service)),0)); + BleResponse> response = new BleResponse> + { + IsSuccess = true, + Error = null, + Data = characteristiclist, + }; + characteristicCallback.Value?.Invoke(this, characteristicCallback.Key, response); + } }, null); } - private void ConnectInternal(WclBleGattThread gattClient) - { - //Task.Run(() => - //{ - //int num = gattClient.Connect(); - //Debug.Log("连接设备返回" + num); - - - //}); - } - + //设备断开连接 public void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback) { - //var gattThread = this.wclBleMainThread.GetGattThread(peripheral); - //if(gattThread != null && gattThread.CanLoadWork) - //{ - // this.callbacks.Remove(peripheral); - // this.servicesCallbacks.Remove(peripheral); - // this.characteristicNotificationCallbacks.Remove(peripheral); - - // this.disconnectedCallback.Add(peripheral, callback); - // gattThread.Discounect(); - //} + BluetoothLEHardwareInterface.DisconnectPeripheral(peripheral.Address, (address) => + { + //peripheralDisconnectedEvent(this, peripheral, null, true); + callback?.Invoke(); + }); } - public static BleMobileInterface GetInterface() { if(hwInterface == null) @@ -294,223 +282,73 @@ namespace Assets.Scripts.Ble return hwInterface; } - + //扫描设备 public void StartScan(Action discoveredCallBack) { pCache.Clear(); _discoveredCallback = discoveredCallBack; bleMobileThread.StartWatcher(); } - - private void ManagerStatusChanged(WclBleMainThread sender, WclBleManagerStatus status) - { - //this.BleState = BleMobileInterface.StateFromNativeState(status); - //Debug.Log("win hw:" + status); - - } - - private void GattConnected(WclBleGattThread gattClient, BleResponse response) - { - //Debug.Log($"gatt connected { response.ToString() }"); - //if (!response.IsSuccess) - //{ - // gattClient.Stop(); - - // this.callbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); - // this.callbacks.Remove(gattClient.Peripheral); - // return; - //} - //this.callbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); - //this.callbacks.Remove(gattClient.Peripheral); - } - - private void CleanUpPeripheral(BlePeripheralInfo peripheralInfo) - { - //this.callbacks.Clear() - } - - private void GattDisconnected(WclBleGattThread gattClient, BleResponse response) - { - //Debug.Log($"gatt disconnected { gattClient.Peripheral.Name }"); - - //this.callbacks.Remove(gattClient.Peripheral); - //this.servicesCallbacks.Remove(gattClient.Peripheral); - //this.characteristicNotificationCallbacks.Remove(gattClient.Peripheral); - ////App.MainDeviceAdapter.PrintStatus(); - - //var manualDisconnect = disconnectedCallback.ContainsKey(gattClient.Peripheral); - //this.peripheralDisconnectedEvent(this, gattClient.Peripheral, response, manualDisconnect); - - ////App.MainDeviceAdapter.PrintStatus(); - //if (disconnectedCallback.ContainsKey(gattClient.Peripheral)) - //{ - // disconnectedCallback[gattClient.Peripheral].Invoke(); - // disconnectedCallback.Remove(gattClient.Peripheral); - //} - ////this.pCache.Remove(gattClient.Peripheral.Address); - - - - } - private void GattServicesDiscovered(WclBleGattThread gattClient, BleResponse> response) - { - ////Debug.Log("services discovered"); - ////this.callbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); - - ////foreach (var item in response.Data) - ////{ - //// Debug.Log(item.ToString()); - ////} - - //if (this.servicesCallbacks.ContainsKey(gattClient.Peripheral)) - //{ - // this.servicesCallbacks[gattClient.Peripheral].Invoke(this, gattClient.Peripheral, response); - //} - } - - private void GattCharacteristicsDiscovered(WclBleGattThread gattClient, BleServiceInfo service, BleResponse> response) - { - //Debug.Log("characteristics discovered"); - - if (this.characteristicsDiscoveredCallbacks.ContainsKey(service)) - { - this.characteristicsDiscoveredCallbacks[service].Invoke(this, service, response); - } - } - - private void GattCharacteristicSubscribed(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) - { - ////Debug.Log("characteristics subscribed"); - //if (this.characteristicNotificationCallbacks.ContainsKey(gattClient.Peripheral)) - //{ - // this.characteristicNotificationCallbacks[gattClient.Peripheral].Invoke(this, characteristic, response); - //} - } - private void GattCharacteristicRead(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) - { - //Debug.Log("characteristic read"); - - //if (this.characteristicReadCallbacks.ContainsKey(characteristic)) - //{ - // this.characteristicReadCallbacks[characteristic].Invoke(this, characteristic, response); - // this.characteristicReadCallbacks.Remove(characteristic); - //} - - //this.characteristicReadEvent.Invoke(this, characteristic, response); - } - - private void GattCharacteristicWrote(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) - { - Debug.Log("characteristic wrote"); - } - private void GattCharacteristicChanged(WclBleGattThread gattClient, BleCharacteristicInfo characteristic, BleResponse response) - { - ////Debug.Log("characteristic changed"); - //if(this.wclBleMainThread.GetGattThread(characteristic.Peripheral) != null) - //{ - // this.characteristicReadEvent.Invoke(this, characteristic, response); - //} - } - + //发现服务列表 public void DiscoverServices(BlePeripheralInfo peripheral, Action>> callback) { this.servicesCallbacks.Add(peripheral, callback); - if (servicelist.Count > 0) - { - BleResponse> response = new BleResponse> - { - IsSuccess = true, - Error = null, - Data = (List)servicelist, - }; - - callback.Invoke(this, peripheral, response); - return; - } } - + //发现特征值 public void DiscoverCharacteristic(BleServiceInfo service, CharacteristicsDiscoveredCallback callback) { - //WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(service.Peripheral); - //if(gattThread == null) - //{ - // return; - //} - //if (!this.characteristicsDiscoveredCallbacks.ContainsKey(service)) - //{ - // this.characteristicsDiscoveredCallbacks.Add(service, callback); - //} - //int num = gattThread.DiscoverCharacteristics(service); - //if (WclBleErrors.IsSuccessCode(num)) - //{ - // return; - //} - //BleResponse> response = new BleResponse> - //{ - // IsSuccess = false, - // Error = new BleHwInterfaceError(new int?(num), "WclBleGattClientErrorDomain", string.Format("Error discovering characteristics - {0}", num)) - //}; - //this.GattCharacteristicsDiscovered(gattThread, service, response); + this.characteristicsDiscoveredCallbacks.Add(service, callback); } - + //订阅特征值 public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action callback) { - //WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral); - - //this.characteristicNotificationCallbacks.Add(gattThread.Peripheral, callback); - //int num = gattThread.SubscribeCharacteristic(characteristic); - //if (WclBleErrors.IsSuccessCode(num)) - //{ - // return; - //} - //BleResponse> response = new BleResponse> - //{ - // IsSuccess = false, - // Error = new BleHwInterfaceError(new int?(num), "WclBleGattClientErrorDomain", string.Format("Error subscribing characteristic - {0}", num)) - //}; - //this.GattCharacteristicSubscribed(gattThread, characteristic, response); + this.characteristicNotificationCallbacks.Add(characteristic.Peripheral, callback); + BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(characteristic.Peripheral.Address, characteristic.Service.ToString(), characteristic.Id.ToString(), null, (deviceAddress, characteristric, bytes) => + { + if (characteristicReadEvent != null) + { + BleResponse response = new BleResponse + { + IsSuccess = true, + Error = null, + Data = bytes, + }; + characteristicReadEvent.Invoke(this, characteristic, response); + } + }); } - + //写入特征值 public void WriteCharacteristic(BleCharacteristicInfo characteristic, byte[] data) { - //var gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral); - //if(gattThread == null) - //{ - // return; - //} + BluetoothLEHardwareInterface.WriteCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), data, data.Length, false, (characteristicUUID) => { - //int num = gattThread.WriteCharacteristic(characteristic, data); - //if (WclBleErrors.IsSuccessCode(num)) - //{ - // Debug.Log("设置命令成功"); - // return; - //} + BluetoothLEHardwareInterface.Log("Write Succeeded"); + }); } public void Dispose() { - //this.wclBleMainThread.ManagerStatusChanged -= ManagerStatusChanged; - //this.wclBleMainThread.ScanInfoReceived -= WatcherScanInfoReceived; - //this.wclBleMainThread.Stop(); - //this.wclBleMainThread = null; - //hwInterface = null; - //pCache.Clear(); + bleMobileThread.ManagerInitialized -= BleMobileThread_ManagerInitialized; + bleMobileThread.ManagerStatusChanged -= ManagerStatusChanged; + bleMobileThread.ScanInfoReceived -= WatcherScanInfoReceived; + bleMobileThread.Stop(); + bleMobileThread = null; + hwInterface = null; + pCache.Clear(); } public void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback) { - //WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral); - //if(gattThread == null) - //{ - // return; - //} - //this.characteristicReadCallbacks.Add(characteristic, callback); - //int num = gattThread.ReadCharacteristicValue(characteristic); - //if (WclBleErrors.IsSuccessCode(num)) - //{ - // return; - //} + BluetoothLEHardwareInterface.ReadCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), (c, bytes) => { + BleResponse response = new BleResponse + { + IsSuccess = true, + Error = null, + Data = bytes, + }; + callback?.Invoke(this, characteristic, response); + }); } private static BleState StateFromNativeState(WclBleManagerStatus status) diff --git a/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs b/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs index 3274d7a5..a9db13d0 100644 --- a/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs +++ b/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs @@ -3,64 +3,78 @@ using System.Timers; namespace Assets.Scripts.Devices.Ble { - public class BleMobileThread + internal class BleMobileThread { - public delegate void WclAdvertisementPacketDelegate(BleMobileThread sender, string address, string name, int rssi, string type); - public BleMobileThread.WclAdvertisementPacketDelegate ScanInfoReceived; - private Timer timer { get; set; } - public BleMobileThread() { - //初始蓝牙 - BluetoothLEHardwareInterface.Initialize(true, false, () => { - - }, - (error) => { - - BluetoothLEHardwareInterface.Log("Error: " + error); - - if (error.Contains("Bluetooth LE Not Enabled")) - BluetoothLEHardwareInterface.BluetoothEnable(true); - }); - } - bool startScan = true; - public void StartWatcher() { - //if (timer == null) - //{ - // timer = new Timer(); - // timer.Interval = 500; - // timer.Elapsed += Timer_Elapsed; - //} - //if (!timer.Enabled) - //{ - // timer.Start(); - //} "0000180D-0000-1000-8000-00805F9B34FB" - var ss = new string[] {"00001826-0000-1000-8000-00805F9B34FB","0000180D-0000-1000-8000-00805F9B34FB", "6e40fec1-b5a3-f393-e0a9-e50e24dcca9e" }; - BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(ss, (s,a)=> { - BluetoothLEHardwareInterface.Log(s); - }, (address, name, rssi, bytes) => - { - ScanInfoReceived?.Invoke(this, address, name, rssi,"trainer"); - }, true); - } - - public void StopWatcher() + public delegate void WclInitializedDelegate(BleMobileThread sender); + private BleMobileThread.WclInitializedDelegate managerInitialized; + public event BleMobileThread.WclInitializedDelegate ManagerInitialized { - if (timer.Enabled) + add { - timer.Stop(); + this.managerInitialized += value; + } + remove + { + this.managerInitialized -= value; } } - private void Timer_Elapsed(object sender, ElapsedEventArgs e) + public delegate void WclAdvertisementPacketDelegate(BleMobileThread sender, string address, string name, int rssi, string[] uuids); + public BleMobileThread.WclAdvertisementPacketDelegate ScanInfoReceived; + + internal delegate void ManagerStatusChangedCallback(BleMobileThread thread, WclBleManagerStatus status); + private BleMobileThread.ManagerStatusChangedCallback managerStatusChanged; + public event BleMobileThread.ManagerStatusChangedCallback ManagerStatusChanged { - //if (startScan) - //{ - // startScan = false; - // BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null, null, null,(address, name, rssi, bytes) => - // { + add + { + this.managerStatusChanged += value; + } + remove + { + this.managerStatusChanged -= value; + } + } - // ScanInfoReceived?.Invoke(this, address, name, rssi); - // }, true); - //} - } + internal BleMobileThread() { + var self = this; + //初始蓝牙 + BluetoothLEHardwareInterface.Initialize(true, false, () => { + managerInitialized?.Invoke(self); + }, + (error) => { + BluetoothLEHardwareInterface.Log("Error: " + error); + if (error.Contains("Bluetooth LE Not Enabled")) + BluetoothLEHardwareInterface.BluetoothEnable(true); + }, (status) => { + + var statusEnum = WclBleManagerStatus.RadioOn; + switch (status) + { + case 13: + statusEnum = WclBleManagerStatus.RadioOff; + break; + case 11: + statusEnum = WclBleManagerStatus.RadioOn; + break; + } + if (managerStatusChanged != null) + { + managerStatusChanged.Invoke(self, statusEnum); + } + }); + } + + public void StartWatcher() { + BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null, null, (address, name, rssi, bytes) => + { + ScanInfoReceived?.Invoke(this, address, name, rssi, bytes); + }, true); + } + + public void Stop() + { + BluetoothLEHardwareInterface.StopScan(); + } } } diff --git a/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs b/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs index 94388d22..d342a727 100644 --- a/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs +++ b/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs @@ -56,7 +56,7 @@ namespace Assets.Scenes.Ride.Scripts weight = App.CurrentUser.Weight; bicycleWeight = App.CurrentUser.BicycleWeight; //#if UNITY_EDITOR - power = 500; + //power = 500; //#endif mainController.TrackResistance(currentSlope * App.RideSetting.Sensitivity / 100); }