From 0457cefd7a6803fb08047bf030c7a882cec01bad Mon Sep 17 00:00:00 2001 From: Thad House Date: Sun, 3 Mar 2024 11:04:53 -0800 Subject: [PATCH] Add sim callback wrappers --- src/hal/Handles/GlobalSimCallbackWrapper.cs | 32 ++++++++++ src/hal/Handles/IndexedSimCallbackWrapper.cs | 34 +++++++++++ src/hal/Handles/SimCallbacks.cs | 64 ++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 src/hal/Handles/GlobalSimCallbackWrapper.cs create mode 100644 src/hal/Handles/IndexedSimCallbackWrapper.cs create mode 100644 src/hal/Handles/SimCallbacks.cs diff --git a/src/hal/Handles/GlobalSimCallbackWrapper.cs b/src/hal/Handles/GlobalSimCallbackWrapper.cs new file mode 100644 index 00000000..6ae8a86c --- /dev/null +++ b/src/hal/Handles/GlobalSimCallbackWrapper.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; + +using unsafe HalNativeNotifyCallback = delegate* unmanaged[Cdecl]; + +namespace WPIHal.Handles; + +public readonly struct GlobalSimCallbackWrapper : IDisposable +{ + public required GCHandle DelegateHandle { get; init; } + public required int NativeHandle { get; init; } + public unsafe required delegate* managed Cancel { get; init; } + + public unsafe void Dispose() + { + Cancel(NativeHandle); + DelegateHandle.Free(); + } + + public unsafe GlobalSimCallbackWrapper(NotifyCallback callback, bool immediateNotify, delegate* managed register, delegate* managed cancel) + { + DelegateHandle = GCHandle.Alloc(callback); + NativeHandle = register(&SimCallbacks.HalNotifyCallback, (void*)GCHandle.ToIntPtr(DelegateHandle), immediateNotify); + Cancel = cancel; + } + + public unsafe GlobalSimCallbackWrapper(NotifyCallbackUtf8 callback, bool immediateNotify, delegate* managed register, delegate* managed cancel) + { + DelegateHandle = GCHandle.Alloc(callback); + NativeHandle = register(&SimCallbacks.HalNotifyCallback, (void*)GCHandle.ToIntPtr(DelegateHandle), immediateNotify); + Cancel = cancel; + } +} diff --git a/src/hal/Handles/IndexedSimCallbackWrapper.cs b/src/hal/Handles/IndexedSimCallbackWrapper.cs new file mode 100644 index 00000000..58467bc6 --- /dev/null +++ b/src/hal/Handles/IndexedSimCallbackWrapper.cs @@ -0,0 +1,34 @@ +using System.Runtime.InteropServices; +using unsafe HalNativeNotifyCallback = delegate* unmanaged[Cdecl]; + +namespace WPIHal.Handles; + +public readonly struct IndexedSimCallbackWrapper : IDisposable +{ + public required GCHandle DelegateHandle { get; init; } + public required int NativeHandle { get; init; } + public required int Index { get; init; } + public unsafe required delegate* managed Cancel { get; init; } + + public unsafe IndexedSimCallbackWrapper(int index, NotifyCallback callback, bool immediateNotify, delegate* managed register, delegate* managed cancel) + { + DelegateHandle = GCHandle.Alloc(callback); + NativeHandle = register(index, &SimCallbacks.HalNotifyCallback, (void*)GCHandle.ToIntPtr(DelegateHandle), immediateNotify); + Index = index; + Cancel = cancel; + } + + public unsafe IndexedSimCallbackWrapper(int index, NotifyCallbackUtf8 callback, bool immediateNotify, delegate* managed register, delegate* managed cancel) + { + DelegateHandle = GCHandle.Alloc(callback); + NativeHandle = register(index, &SimCallbacks.HalNotifyCallback, (void*)GCHandle.ToIntPtr(DelegateHandle), immediateNotify); + Index = index; + Cancel = cancel; + } + + public unsafe void Dispose() + { + Cancel(Index, NativeHandle); + DelegateHandle.Free(); + } +} diff --git a/src/hal/Handles/SimCallbacks.cs b/src/hal/Handles/SimCallbacks.cs new file mode 100644 index 00000000..b09cfb52 --- /dev/null +++ b/src/hal/Handles/SimCallbacks.cs @@ -0,0 +1,64 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace WPIHal.Handles; + +public delegate void NotifyCallback(string name, HalValue value); +public delegate void NotifyCallbackUtf8(ReadOnlySpan name, HalValue value); + +public delegate void BufferCallback(string name, Span buffer); +public delegate void BufferCallbackUtf8(ReadOnlySpan name, Span buffer); + +public delegate void ConstBufferCallback(string name, ReadOnlySpan buffer); +public delegate void ConstBufferCallbackUtf8(ReadOnlySpan name, ReadOnlySpan buffer); + +public class SimCallbacks +{ + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + public static unsafe void HalNotifyCallback(byte* name, void* param, HalValue* value) + { + GCHandle handle = GCHandle.FromIntPtr((nint)param); + if (handle.Target is NotifyCallback stringCallback) + { + string n = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((nint)name) ?? ""; + stringCallback(n, *value); + } + else if (handle.Target is NotifyCallbackUtf8 utf8Callback) + { + ReadOnlySpan n = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(name); + utf8Callback(n, *value); + } + } + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + public static unsafe void HalBufferCallback(byte* name, void* param, byte* buffer, uint count) + { + GCHandle handle = GCHandle.FromIntPtr((nint)param); + if (handle.Target is BufferCallback stringCallback) + { + string n = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((nint)name) ?? ""; + stringCallback(n, new(buffer, (int)count)); + } + else if (handle.Target is BufferCallbackUtf8 utf8Callback) + { + ReadOnlySpan n = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(name); + utf8Callback(n, new(buffer, (int)count)); + } + } + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + public static unsafe void HalConstBufferCallback(byte* name, void* param, byte* buffer, uint count) + { + GCHandle handle = GCHandle.FromIntPtr((nint)param); + if (handle.Target is ConstBufferCallback stringCallback) + { + string n = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((nint)name) ?? ""; + stringCallback(n, new(buffer, (int)count)); + } + else if (handle.Target is ConstBufferCallbackUtf8 utf8Callback) + { + ReadOnlySpan n = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(name); + utf8Callback(n, new(buffer, (int)count)); + } + } +}