diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBCentralManager.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBCentralManager.cs index 971ed20..ec54ff1 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBCentralManager.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBCentralManager.cs @@ -18,6 +18,15 @@ void DidDiscoverPeripheral(CBCentralManager central, CBPeripheral peripheral, in void DidUpdateState(CBCentralManager central); } + internal interface INativeCentralManagerDelegate + { + void DidConnect(string peripheralId) { } + void DidDisconnectPeripheral(string peripheralId, CBError error) { } + void DidFailToConnect(string peripheralId, CBError error) { } + void DidDiscoverPeripheral(SafeNativePeripheralHandle peripheral, int rssi) { } + void DidUpdateState(CBManagerState state) { } + } + /// /// An object that scans for, discovers, connects to, and manages peripherals. /// https://developer.apple.com/documentation/corebluetooth/cbcentralmanager @@ -189,6 +198,7 @@ public void Dispose() { if (_disposed) return; + _nativeCentralManagerProxy?.Dispose(); _handle?.Dispose(); foreach (var peripheral in _peripherals.Values) { diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheral.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheral.cs index ac85a78..775b3c6 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheral.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheral.cs @@ -27,6 +27,19 @@ void DidUpdateName(CBPeripheral peripheral) { } void DidModifyServices(CBPeripheral peripheral, CBService[] services) { } } + internal interface INativePeripheralDelegate + { + void DidDiscoverServices(string[] serviceUUIDs, CBError error) { } + void DidDiscoverCharacteristics(string serviceUUID, string[] characteristicUUIDs, CBError error) { } + void DidUpdateValueForCharacteristic(string serviceUUID, string characteristicUUID, byte[] data, CBError error) { } + void DidWriteValueForCharacteristic(string serviceUUID, string characteristicUUID, CBError error) { } + void IsReadyToSendWriteWithoutResponse() { } + void DidUpdateNotificationStateForCharacteristic(string serviceUUID, string characteristicUUID, bool enabled, CBError error) { } + void DidReadRSSI(int rssi, CBError error) { } + void DidUpdateName() { } + void DidModifyServices(string[] invalidatedServiceUUIDs) { } + } + /// /// A remote peripheral device. /// https://developer.apple.com/documentation/corebluetooth/cbperipheral @@ -315,6 +328,7 @@ public void Dispose() { if (_disposed) return; + _nativePeripheral?.Dispose(); Handle?.Dispose(); _disposed = true; diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheralManager.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheralManager.cs index 4084297..ce0fb4c 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheralManager.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBPeripheralManager.cs @@ -16,6 +16,18 @@ void DidReceiveReadRequest(CBPeripheralManager peripheral, CBATTRequest request) void DidReceiveWriteRequests(CBPeripheralManager peripheral, CBATTRequest[] requests) { } } + internal interface INativePeripheralManagerDelegate + { + void DidUpdateState(CBManagerState state) { } + void DidAddService(string serviceUUID, CBError error) { } + void DidStartAdvertising(CBError error) { } + void DidSubscribeToCharacteristic(SafeNativeCentralHandle central, string serviceUUID, string characteristicUUID) { } + void DidUnsubscribeFromCharacteristic(SafeNativeCentralHandle central, string serviceUUID, string characteristicUUID) { } + void IsReadyToUpdateSubscribers() { } + void DidReceiveReadRequest(SafeNativeATTRequestHandle request) { } + void DidReceiveWriteRequests(SafeNativeATTRequestsHandle requests) { } + } + internal interface IPeripheralManagerData { void AddCentral(CBCentral central); @@ -283,6 +295,7 @@ public void Dispose() { if (_disposed) return; + _nativePeripheralManagerProxy.Dispose(); _handle?.Dispose(); foreach (var central in _centrals.Values) { diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativeCentralManagerProxy.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativeCentralManagerProxy.cs index e663718..c190c52 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativeCentralManagerProxy.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativeCentralManagerProxy.cs @@ -1,15 +1,24 @@ +using System; +using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; namespace CoreBluetooth { - internal class NativeCentralManagerProxy + internal class NativeCentralManagerProxy : IDisposable { + readonly static Dictionary s_centralManagerDelegateMap = new Dictionary(); + readonly SafeNativeCentralManagerHandle _handle; public NativeCentralManagerProxy(SafeNativeCentralManagerHandle handle, INativeCentralManagerDelegate centralManagerDelegate) { _handle = handle; - _handle.SetDelegate(centralManagerDelegate); + if (centralManagerDelegate != null) + { + s_centralManagerDelegateMap[handle.DangerousGetHandle()] = centralManagerDelegate; + } + RegisterHandlers(); } public void Connect(CBPeripheral peripheral) @@ -52,5 +61,66 @@ public bool IsScanning() { return NativeMethods.cb4u_central_manager_is_scanning(_handle); } + + void RegisterHandlers() + { + NativeMethods.cb4u_central_manager_register_handlers( + _handle, + DidConnect, + DidDisconnectPeripheral, + DidFailToConnect, + DidDiscoverPeripheral, + DidUpdateState + ); + } + + public void Dispose() + { + s_centralManagerDelegateMap.Remove(_handle.DangerousGetHandle()); + } + + static INativeCentralManagerDelegate GetDelegate(IntPtr centralPtr) + { + return s_centralManagerDelegateMap.GetValueOrDefault(centralPtr); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidConnectHandler))] + internal static void DidConnect(IntPtr centralPtr, IntPtr peripheralIdPtr) + { + GetDelegate(centralPtr)?.DidConnect(Marshal.PtrToStringUTF8(peripheralIdPtr)); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidDisconnectPeripheralHandler))] + public static void DidDisconnectPeripheral(IntPtr centralPtr, IntPtr peripheralIdPtr, int errorCode) + { + GetDelegate(centralPtr)?.DidDisconnectPeripheral( + Marshal.PtrToStringUTF8(peripheralIdPtr), + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidFailToConnectHandler))] + public static void DidFailToConnect(IntPtr centralPtr, IntPtr peripheralIdPtr, int errorCode) + { + GetDelegate(centralPtr)?.DidFailToConnect( + Marshal.PtrToStringUTF8(peripheralIdPtr), + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidDiscoverPeripheralHandler))] + public static void DidDiscoverPeripheral(IntPtr centralPtr, IntPtr peripheralPtr, int rssi) + { + GetDelegate(centralPtr)?.DidDiscoverPeripheral( + new SafeNativePeripheralHandle(peripheralPtr), + rssi + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidUpdateStateHandler))] + public static void DidUpdateState(IntPtr centralPtr, CBManagerState state) + { + GetDelegate(centralPtr)?.DidUpdateState(state); + } } } diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralManagerProxy.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralManagerProxy.cs index 73e7571..0e5028b 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralManagerProxy.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralManagerProxy.cs @@ -1,16 +1,25 @@ using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; namespace CoreBluetooth { - internal class NativePeripheralManagerProxy + internal class NativePeripheralManagerProxy : IDisposable { + static Dictionary s_peripheralManagerDelegateMap = new Dictionary(); + readonly SafeNativePeripheralManagerHandle _handle; internal NativePeripheralManagerProxy(SafeNativePeripheralManagerHandle handle, INativePeripheralManagerDelegate peripheralManagerDelegate) { _handle = handle; - _handle.SetDelegate(peripheralManagerDelegate); + if (peripheralManagerDelegate != null) + { + s_peripheralManagerDelegateMap[handle.DangerousGetHandle()] = peripheralManagerDelegate; + } + + RegisterHandlers(); } internal void AddService(SafeNativeMutableServiceHandle service) @@ -90,5 +99,93 @@ internal void RespondToRequest(CBATTRequest request, CBATTError result) { NativeMethods.cb4u_peripheral_manager_respond_to_request(_handle, request.Handle, (int)result); } + + void RegisterHandlers() + { + NativeMethods.cb4u_peripheral_manager_register_handlers( + _handle, + DidUpdateState, + DidAddService, + DidStartAdvertising, + DidSubscribeToCharacteristic, + DidUnsubscribeFromCharacteristic, + IsReadyToUpdateSubscribers, + DidReceiveReadRequest, + DidReceiveWriteRequests + ); + } + + public void Dispose() + { + s_peripheralManagerDelegateMap.Remove(_handle.DangerousGetHandle()); + } + + static INativePeripheralManagerDelegate GetDelegate(IntPtr peripheralPtr) + { + return s_peripheralManagerDelegateMap.GetValueOrDefault(peripheralPtr); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidUpdateStateHandler))] + public static void DidUpdateState(IntPtr peripheralPtr, CBManagerState state) + { + GetDelegate(peripheralPtr)?.DidUpdateState(state); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidAddServiceHandler))] + public static void DidAddService(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, int errorCode) + { + GetDelegate(peripheralPtr)?.DidAddService( + Marshal.PtrToStringUTF8(serviceUUIDPtr), + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidStartAdvertisingHandler))] + public static void DidStartAdvertising(IntPtr peripheralPtr, int errorCode) + { + GetDelegate(peripheralPtr)?.DidStartAdvertising(CBError.CreateOrNullFromCode(errorCode)); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidSubscribeToCharacteristicHandler))] + public static void DidSubscribeToCharacteristic(IntPtr peripheralPtr, IntPtr centralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr) + { + GetDelegate(peripheralPtr)?.DidSubscribeToCharacteristic( + new SafeNativeCentralHandle(centralPtr), + Marshal.PtrToStringUTF8(serviceUUIDPtr), + Marshal.PtrToStringUTF8(characteristicUUIDPtr) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidUnsubscribeFromCharacteristicHandler))] + public static void DidUnsubscribeFromCharacteristic(IntPtr peripheralPtr, IntPtr centralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr) + { + GetDelegate(peripheralPtr)?.DidUnsubscribeFromCharacteristic( + new SafeNativeCentralHandle(centralPtr), + Marshal.PtrToStringUTF8(serviceUUIDPtr), + Marshal.PtrToStringUTF8(characteristicUUIDPtr) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerIsReadyToUpdateSubscribersHandler))] + public static void IsReadyToUpdateSubscribers(IntPtr peripheralPtr) + { + GetDelegate(peripheralPtr)?.IsReadyToUpdateSubscribers(); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidReceiveReadRequestHandler))] + public static void DidReceiveReadRequest(IntPtr peripheralPtr, IntPtr requestPtr) + { + GetDelegate(peripheralPtr)?.DidReceiveReadRequest( + new SafeNativeATTRequestHandle(requestPtr) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidReceiveWriteRequestsHandler))] + public static void DidReceiveWriteRequests(IntPtr peripheralPtr, IntPtr requestsPtr) + { + GetDelegate(peripheralPtr)?.DidReceiveWriteRequests( + new SafeNativeATTRequestsHandle(requestsPtr) + ); + } } } diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralProxy.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralProxy.cs index 8a19f29..5dfabad 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralProxy.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/NativePeripheralProxy.cs @@ -1,19 +1,27 @@ using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; namespace CoreBluetooth { - internal class NativePeripheralProxy + internal class NativePeripheralProxy : IDisposable { + readonly static Dictionary s_nativePeripheralDelegateMap = new Dictionary(); + readonly SafeNativePeripheralHandle _handle; - internal NativePeripheralProxy(SafeNativePeripheralHandle handle, INativePeripheralDelegate peripheralDelegate) + public NativePeripheralProxy(SafeNativePeripheralHandle handle, INativePeripheralDelegate peripheralDelegate) { _handle = handle; - _handle.SetDelegate(peripheralDelegate); + if (peripheralDelegate != null) + { + s_nativePeripheralDelegateMap[handle.DangerousGetHandle()] = peripheralDelegate; + } + RegisterHandlers(); } - internal string Identifier + public string Identifier { get { @@ -23,7 +31,7 @@ internal string Identifier } } - internal string Name + public string Name { get { @@ -38,7 +46,7 @@ internal string Name } } - internal void DiscoverServices(string[] serviceUUIDs) + public void DiscoverServices(string[] serviceUUIDs) { if (serviceUUIDs != null) { @@ -55,7 +63,7 @@ internal void DiscoverServices(string[] serviceUUIDs) ); } - internal void DiscoverCharacteristics(string[] characteristicUUIDs, CBService service) + public void DiscoverCharacteristics(string[] characteristicUUIDs, CBService service) { if (characteristicUUIDs != null) { @@ -75,7 +83,7 @@ internal void DiscoverCharacteristics(string[] characteristicUUIDs, CBService se ExceptionUtils.ThrowIfServiceNotFound(result, service.UUID); } - internal void ReadValue(CBCharacteristic characteristic) + public void ReadValue(CBCharacteristic characteristic) { int result = NativeMethods.cb4u_peripheral_read_characteristic_value( _handle, @@ -87,7 +95,7 @@ internal void ReadValue(CBCharacteristic characteristic) ExceptionUtils.ThrowIfCharacteristicNotFound(result, characteristic.UUID); } - internal void WriteValue(byte[] data, CBCharacteristic characteristic, CBCharacteristicWriteType writeType) + public void WriteValue(byte[] data, CBCharacteristic characteristic, CBCharacteristicWriteType writeType) { if (data == null) throw new ArgumentNullException(nameof(data)); @@ -106,12 +114,12 @@ internal void WriteValue(byte[] data, CBCharacteristic characteristic, CBCharact ExceptionUtils.ThrowIfCharacteristicNotFound(result, characteristic.UUID); } - internal int GetMaximumWriteValueLength(CBCharacteristicWriteType writeType) + public int GetMaximumWriteValueLength(CBCharacteristicWriteType writeType) { return NativeMethods.cb4u_peripheral_maximum_write_value_length(_handle, (int)writeType); } - internal void SetNotifyValue(bool enabled, CBCharacteristic characteristic) + public void SetNotifyValue(bool enabled, CBCharacteristic characteristic) { int result = NativeMethods.cb4u_peripheral_set_notify_value( _handle, @@ -124,7 +132,7 @@ internal void SetNotifyValue(bool enabled, CBCharacteristic characteristic) ExceptionUtils.ThrowIfCharacteristicNotFound(result, characteristic.UUID); } - internal CBPeripheralState State + public CBPeripheralState State { get { @@ -133,7 +141,7 @@ internal CBPeripheralState State } } - internal bool CanSendWriteWithoutResponse + public bool CanSendWriteWithoutResponse { get { @@ -141,9 +149,121 @@ internal bool CanSendWriteWithoutResponse } } - internal void ReadRSSI() + public void ReadRSSI() { NativeMethods.cb4u_peripheral_read_rssi(_handle); } + + void RegisterHandlers() + { + NativeMethods.cb4u_peripheral_register_handlers( + _handle, + DidDiscoverServices, + DidDiscoverCharacteristics, + DidUpdateValueForCharacteristic, + DidWriteValueForCharacteristic, + IsReadyToSendWriteWithoutResponse, + DidUpdateNotificationStateForCharacteristic, + DidReadRSSI, + DidUpdateName, + DidModifyServices + ); + } + + public void Dispose() + { + s_nativePeripheralDelegateMap.Remove(_handle.DangerousGetHandle()); + } + + static INativePeripheralDelegate GetDelegate(IntPtr peripheralPtr) + { + return s_nativePeripheralDelegateMap.GetValueOrDefault(peripheralPtr); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidDiscoverServicesHandler))] + public static void DidDiscoverServices(IntPtr peripheralPtr, IntPtr commaSeparatedServiceUUIDsPtr, int errorCode) + { + string commaSeparatedServiceUUIDs = Marshal.PtrToStringUTF8(commaSeparatedServiceUUIDsPtr); + GetDelegate(peripheralPtr)?.DidDiscoverServices( + commaSeparatedServiceUUIDs.Split(','), + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidDiscoverCharacteristicsHandler))] + public static void DidDiscoverCharacteristics(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr commaSeparatedCharacteristicUUIDsPtr, int errorCode) + { + string commaSeparatedCharacteristicUUIDs = Marshal.PtrToStringUTF8(commaSeparatedCharacteristicUUIDsPtr); + GetDelegate(peripheralPtr)?.DidDiscoverCharacteristics( + Marshal.PtrToStringUTF8(serviceUUIDPtr), + commaSeparatedCharacteristicUUIDs.Split(','), + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidUpdateValueForCharacteristicHandler))] + public static void DidUpdateValueForCharacteristic(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr, IntPtr dataPtr, int dataLength, int errorCode) + { + var dataBytes = new byte[dataLength]; + Marshal.Copy(dataPtr, dataBytes, 0, dataLength); + + GetDelegate(peripheralPtr)?.DidUpdateValueForCharacteristic( + Marshal.PtrToStringUTF8(serviceUUIDPtr), + Marshal.PtrToStringUTF8(characteristicUUIDPtr), + dataBytes, + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidWriteValueForCharacteristicHandler))] + public static void DidWriteValueForCharacteristic(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr, int errorCode) + { + GetDelegate(peripheralPtr)?.DidWriteValueForCharacteristic( + Marshal.PtrToStringUTF8(serviceUUIDPtr), + Marshal.PtrToStringUTF8(characteristicUUIDPtr), + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralIsReadyToSendWriteWithoutResponseHandler))] + public static void IsReadyToSendWriteWithoutResponse(IntPtr peripheralPtr) + { + GetDelegate(peripheralPtr)?.IsReadyToSendWriteWithoutResponse(); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidUpdateNotificationStateForCharacteristicHandler))] + public static void DidUpdateNotificationStateForCharacteristic(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr, int notificationState, int errorCode) + { + GetDelegate(peripheralPtr)?.DidUpdateNotificationStateForCharacteristic( + Marshal.PtrToStringUTF8(serviceUUIDPtr), + Marshal.PtrToStringUTF8(characteristicUUIDPtr), + notificationState == 1, + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidReadRSSIHandler))] + public static void DidReadRSSI(IntPtr peripheralPtr, int rssi, int errorCode) + { + GetDelegate(peripheralPtr)?.DidReadRSSI( + rssi, + CBError.CreateOrNullFromCode(errorCode) + ); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidUpdateNameHandler))] + public static void DidUpdateName(IntPtr peripheralPtr) + { + GetDelegate(peripheralPtr)?.DidUpdateName(); + } + + [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidModifyServicesHandler))] + public static void DidModifyServices(IntPtr peripheralPtr, IntPtr commaSeparatedServiceUUIDsPtr) + { + string commaSeparatedServiceUUIDs = Marshal.PtrToStringUTF8(commaSeparatedServiceUUIDsPtr); + GetDelegate(peripheralPtr)?.DidModifyServices( + commaSeparatedServiceUUIDs.Split(',') + ); + } } } diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativeCentralManagerHandle.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativeCentralManagerHandle.cs index 6fab801..14911f2 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativeCentralManagerHandle.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativeCentralManagerHandle.cs @@ -1,112 +1,31 @@ using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace CoreBluetooth { - internal interface INativeCentralManagerDelegate - { - void DidConnect(string peripheralId) { } - void DidDisconnectPeripheral(string peripheralId, CBError error) { } - void DidFailToConnect(string peripheralId, CBError error) { } - void DidDiscoverPeripheral(SafeNativePeripheralHandle peripheral, int rssi) { } - void DidUpdateState(CBManagerState state) { } - } - internal class SafeNativeCentralManagerHandle : SafeHandleZeroOrMinusOneIsInvalid { - static Dictionary s_centralManagerDelegateMap = new Dictionary(); - SafeNativeCentralManagerHandle() : base(true) { } static SafeNativeCentralManagerHandle Create(IntPtr options) { - var instance = NativeMethods.cb4u_central_manager_new(options); - instance.RegisterHandlers(); - return instance; + return NativeMethods.cb4u_central_manager_new(options); } - internal static SafeNativeCentralManagerHandle Create(Foundation.SafeNSMutableDictionaryHandle options) + public static SafeNativeCentralManagerHandle Create(Foundation.SafeNSMutableDictionaryHandle options) { return Create(options.DangerousGetHandle()); } - internal static SafeNativeCentralManagerHandle Create() + public static SafeNativeCentralManagerHandle Create() { return Create(IntPtr.Zero); } - void RegisterHandlers() - { - NativeMethods.cb4u_central_manager_register_handlers( - this, - DidConnect, - DidDisconnectPeripheral, - DidFailToConnect, - DidDiscoverPeripheral, - DidUpdateState - ); - } - - internal void SetDelegate(INativeCentralManagerDelegate centralManagerDelegate) - { - s_centralManagerDelegateMap[handle] = centralManagerDelegate; - } - protected override bool ReleaseHandle() { - s_centralManagerDelegateMap.Remove(handle); NativeMethods.cb4u_central_manager_release(handle); return true; } - - static INativeCentralManagerDelegate GetDelegate(IntPtr centralPtr) - { - if (!s_centralManagerDelegateMap.TryGetValue(centralPtr, out var centralManagerDelegate)) - { - return null; - } - return centralManagerDelegate; - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidConnectHandler))] - internal static void DidConnect(IntPtr centralPtr, IntPtr peripheralIdPtr) - { - GetDelegate(centralPtr)?.DidConnect(Marshal.PtrToStringUTF8(peripheralIdPtr)); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidDisconnectPeripheralHandler))] - internal static void DidDisconnectPeripheral(IntPtr centralPtr, IntPtr peripheralIdPtr, int errorCode) - { - GetDelegate(centralPtr)?.DidDisconnectPeripheral( - Marshal.PtrToStringUTF8(peripheralIdPtr), - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidFailToConnectHandler))] - internal static void DidFailToConnect(IntPtr centralPtr, IntPtr peripheralIdPtr, int errorCode) - { - GetDelegate(centralPtr)?.DidFailToConnect( - Marshal.PtrToStringUTF8(peripheralIdPtr), - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidDiscoverPeripheralHandler))] - internal static void DidDiscoverPeripheral(IntPtr centralPtr, IntPtr peripheralPtr, int rssi) - { - GetDelegate(centralPtr)?.DidDiscoverPeripheral( - new SafeNativePeripheralHandle(peripheralPtr), - rssi - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UCentralManagerDidUpdateStateHandler))] - internal static void DidUpdateState(IntPtr centralPtr, CBManagerState state) - { - GetDelegate(centralPtr)?.DidUpdateState(state); - } } } diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralHandle.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralHandle.cs index 8eeace4..ca05f39 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralHandle.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralHandle.cs @@ -1,154 +1,20 @@ using System; -using System.Collections.Generic; using System.Runtime.InteropServices; namespace CoreBluetooth { - internal interface INativePeripheralDelegate - { - void DidDiscoverServices(string[] serviceUUIDs, CBError error) { } - void DidDiscoverCharacteristics(string serviceUUID, string[] characteristicUUIDs, CBError error) { } - void DidUpdateValueForCharacteristic(string serviceUUID, string characteristicUUID, byte[] data, CBError error) { } - void DidWriteValueForCharacteristic(string serviceUUID, string characteristicUUID, CBError error) { } - void IsReadyToSendWriteWithoutResponse() { } - void DidUpdateNotificationStateForCharacteristic(string serviceUUID, string characteristicUUID, bool enabled, CBError error) { } - void DidReadRSSI(int rssi, CBError error) { } - void DidUpdateName() { } - void DidModifyServices(string[] invalidatedServiceUUIDs) { } - } - internal class SafeNativePeripheralHandle : SafeHandle { - static Dictionary s_nativePeripheralDelegateMap = new Dictionary(); - public override bool IsInvalid => handle == IntPtr.Zero; internal SafeNativePeripheralHandle(IntPtr handle) : base(handle, true) { - RegisterHandlers(); - } - - void RegisterHandlers() - { - NativeMethods.cb4u_peripheral_register_handlers( - this, - DidDiscoverServices, - DidDiscoverCharacteristics, - DidUpdateValueForCharacteristic, - DidWriteValueForCharacteristic, - IsReadyToSendWriteWithoutResponse, - DidUpdateNotificationStateForCharacteristic, - DidReadRSSI, - DidUpdateName, - DidModifyServices - ); - } - - internal void SetDelegate(INativePeripheralDelegate peripheralDelegate) - { - s_nativePeripheralDelegateMap[handle] = peripheralDelegate; } protected override bool ReleaseHandle() { - s_nativePeripheralDelegateMap.Remove(handle); NativeMethods.cb4u_peripheral_release(handle); return true; } - - static INativePeripheralDelegate GetDelegate(IntPtr peripheralPtr) - { - if (!s_nativePeripheralDelegateMap.TryGetValue(peripheralPtr, out var peripheralDelegate)) - { - return null; - } - return peripheralDelegate; - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidDiscoverServicesHandler))] - internal static void DidDiscoverServices(IntPtr peripheralPtr, IntPtr commaSeparatedServiceUUIDsPtr, int errorCode) - { - string commaSeparatedServiceUUIDs = Marshal.PtrToStringUTF8(commaSeparatedServiceUUIDsPtr); - GetDelegate(peripheralPtr)?.DidDiscoverServices( - commaSeparatedServiceUUIDs.Split(','), - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidDiscoverCharacteristicsHandler))] - internal static void DidDiscoverCharacteristics(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr commaSeparatedCharacteristicUUIDsPtr, int errorCode) - { - string commaSeparatedCharacteristicUUIDs = Marshal.PtrToStringUTF8(commaSeparatedCharacteristicUUIDsPtr); - GetDelegate(peripheralPtr)?.DidDiscoverCharacteristics( - Marshal.PtrToStringUTF8(serviceUUIDPtr), - commaSeparatedCharacteristicUUIDs.Split(','), - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidUpdateValueForCharacteristicHandler))] - internal static void DidUpdateValueForCharacteristic(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr, IntPtr dataPtr, int dataLength, int errorCode) - { - var dataBytes = new byte[dataLength]; - Marshal.Copy(dataPtr, dataBytes, 0, dataLength); - - GetDelegate(peripheralPtr)?.DidUpdateValueForCharacteristic( - Marshal.PtrToStringUTF8(serviceUUIDPtr), - Marshal.PtrToStringUTF8(characteristicUUIDPtr), - dataBytes, - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidWriteValueForCharacteristicHandler))] - internal static void DidWriteValueForCharacteristic(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr, int errorCode) - { - GetDelegate(peripheralPtr)?.DidWriteValueForCharacteristic( - Marshal.PtrToStringUTF8(serviceUUIDPtr), - Marshal.PtrToStringUTF8(characteristicUUIDPtr), - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralIsReadyToSendWriteWithoutResponseHandler))] - internal static void IsReadyToSendWriteWithoutResponse(IntPtr peripheralPtr) - { - GetDelegate(peripheralPtr)?.IsReadyToSendWriteWithoutResponse(); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidUpdateNotificationStateForCharacteristicHandler))] - internal static void DidUpdateNotificationStateForCharacteristic(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr, int notificationState, int errorCode) - { - GetDelegate(peripheralPtr)?.DidUpdateNotificationStateForCharacteristic( - Marshal.PtrToStringUTF8(serviceUUIDPtr), - Marshal.PtrToStringUTF8(characteristicUUIDPtr), - notificationState == 1, - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidReadRSSIHandler))] - internal static void DidReadRSSI(IntPtr peripheralPtr, int rssi, int errorCode) - { - GetDelegate(peripheralPtr)?.DidReadRSSI( - rssi, - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidUpdateNameHandler))] - internal static void DidUpdateName(IntPtr peripheralPtr) - { - GetDelegate(peripheralPtr)?.DidUpdateName(); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralDidModifyServicesHandler))] - internal static void DidModifyServices(IntPtr peripheralPtr, IntPtr commaSeparatedServiceUUIDsPtr) - { - string commaSeparatedServiceUUIDs = Marshal.PtrToStringUTF8(commaSeparatedServiceUUIDsPtr); - GetDelegate(peripheralPtr)?.DidModifyServices( - commaSeparatedServiceUUIDs.Split(',') - ); - } } } diff --git a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralManagerHandle.cs b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralManagerHandle.cs index bc281ae..01bed52 100644 --- a/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralManagerHandle.cs +++ b/Packages/com.teach310.core-bluetooth-for-unity/Runtime/SafeNativePeripheralManagerHandle.cs @@ -1,33 +1,15 @@ using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace CoreBluetooth { - internal interface INativePeripheralManagerDelegate - { - void DidUpdateState(CBManagerState state) { } - void DidAddService(string serviceUUID, CBError error) { } - void DidStartAdvertising(CBError error) { } - void DidSubscribeToCharacteristic(SafeNativeCentralHandle central, string serviceUUID, string characteristicUUID) { } - void DidUnsubscribeFromCharacteristic(SafeNativeCentralHandle central, string serviceUUID, string characteristicUUID) { } - void IsReadyToUpdateSubscribers() { } - void DidReceiveReadRequest(SafeNativeATTRequestHandle request) { } - void DidReceiveWriteRequests(SafeNativeATTRequestsHandle requests) { } - } - public class SafeNativePeripheralManagerHandle : SafeHandleZeroOrMinusOneIsInvalid { - static Dictionary s_peripheralManagerDelegateMap = new Dictionary(); - SafeNativePeripheralManagerHandle() : base(true) { } internal static SafeNativePeripheralManagerHandle Create(IntPtr options) { - var instance = NativeMethods.cb4u_peripheral_manager_new(options); - instance.RegisterHandlers(); - return instance; + return NativeMethods.cb4u_peripheral_manager_new(options); } internal static SafeNativePeripheralManagerHandle Create(Foundation.SafeNSMutableDictionaryHandle options) @@ -40,103 +22,10 @@ internal static SafeNativePeripheralManagerHandle Create() return Create(IntPtr.Zero); } - void RegisterHandlers() - { - NativeMethods.cb4u_peripheral_manager_register_handlers( - this, - DidUpdateState, - DidAddService, - DidStartAdvertising, - DidSubscribeToCharacteristic, - DidUnsubscribeFromCharacteristic, - IsReadyToUpdateSubscribers, - DidReceiveReadRequest, - DidReceiveWriteRequests - ); - } - - internal void SetDelegate(INativePeripheralManagerDelegate peripheralManagerDelegate) - { - s_peripheralManagerDelegateMap[handle] = peripheralManagerDelegate; - } - protected override bool ReleaseHandle() { - s_peripheralManagerDelegateMap.Remove(handle); NativeMethods.cb4u_peripheral_manager_release(handle); return true; } - - static INativePeripheralManagerDelegate GetDelegate(IntPtr peripheralPtr) - { - if (!s_peripheralManagerDelegateMap.TryGetValue(peripheralPtr, out var peripheralManagerDelegate)) - { - return null; - } - return peripheralManagerDelegate; - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidUpdateStateHandler))] - internal static void DidUpdateState(IntPtr peripheralPtr, CBManagerState state) - { - GetDelegate(peripheralPtr)?.DidUpdateState(state); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidAddServiceHandler))] - internal static void DidAddService(IntPtr peripheralPtr, IntPtr serviceUUIDPtr, int errorCode) - { - GetDelegate(peripheralPtr)?.DidAddService( - Marshal.PtrToStringUTF8(serviceUUIDPtr), - CBError.CreateOrNullFromCode(errorCode) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidStartAdvertisingHandler))] - internal static void DidStartAdvertising(IntPtr peripheralPtr, int errorCode) - { - GetDelegate(peripheralPtr)?.DidStartAdvertising(CBError.CreateOrNullFromCode(errorCode)); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidSubscribeToCharacteristicHandler))] - internal static void DidSubscribeToCharacteristic(IntPtr peripheralPtr, IntPtr centralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr) - { - GetDelegate(peripheralPtr)?.DidSubscribeToCharacteristic( - new SafeNativeCentralHandle(centralPtr), - Marshal.PtrToStringUTF8(serviceUUIDPtr), - Marshal.PtrToStringUTF8(characteristicUUIDPtr) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidUnsubscribeFromCharacteristicHandler))] - internal static void DidUnsubscribeFromCharacteristic(IntPtr peripheralPtr, IntPtr centralPtr, IntPtr serviceUUIDPtr, IntPtr characteristicUUIDPtr) - { - GetDelegate(peripheralPtr)?.DidUnsubscribeFromCharacteristic( - new SafeNativeCentralHandle(centralPtr), - Marshal.PtrToStringUTF8(serviceUUIDPtr), - Marshal.PtrToStringUTF8(characteristicUUIDPtr) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerIsReadyToUpdateSubscribersHandler))] - internal static void IsReadyToUpdateSubscribers(IntPtr peripheralPtr) - { - GetDelegate(peripheralPtr)?.IsReadyToUpdateSubscribers(); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidReceiveReadRequestHandler))] - internal static void DidReceiveReadRequest(IntPtr peripheralPtr, IntPtr requestPtr) - { - GetDelegate(peripheralPtr)?.DidReceiveReadRequest( - new SafeNativeATTRequestHandle(requestPtr) - ); - } - - [AOT.MonoPInvokeCallback(typeof(NativeMethods.CB4UPeripheralManagerDidReceiveWriteRequestsHandler))] - internal static void DidReceiveWriteRequests(IntPtr peripheralPtr, IntPtr requestsPtr) - { - GetDelegate(peripheralPtr)?.DidReceiveWriteRequests( - new SafeNativeATTRequestsHandle(requestsPtr) - ); - } } }