Skip to content

Commit

Permalink
Add sim callback wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
ThadHouse committed Mar 3, 2024
1 parent be30eed commit 0457cef
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/hal/Handles/GlobalSimCallbackWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Runtime.InteropServices;

using unsafe HalNativeNotifyCallback = delegate* unmanaged[Cdecl]<byte*, void*, WPIHal.HalValue*, void>;

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<int, void> Cancel { get; init; }

public unsafe void Dispose()
{
Cancel(NativeHandle);
DelegateHandle.Free();
}

public unsafe GlobalSimCallbackWrapper(NotifyCallback callback, bool immediateNotify, delegate* managed<HalNativeNotifyCallback, void*, bool, int> register, delegate* managed<int, void> 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<HalNativeNotifyCallback, void*, bool, int> register, delegate* managed<int, void> cancel)
{
DelegateHandle = GCHandle.Alloc(callback);
NativeHandle = register(&SimCallbacks.HalNotifyCallback, (void*)GCHandle.ToIntPtr(DelegateHandle), immediateNotify);
Cancel = cancel;
}
}
34 changes: 34 additions & 0 deletions src/hal/Handles/IndexedSimCallbackWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Runtime.InteropServices;
using unsafe HalNativeNotifyCallback = delegate* unmanaged[Cdecl]<byte*, void*, WPIHal.HalValue*, void>;

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<int, int, void> Cancel { get; init; }

public unsafe IndexedSimCallbackWrapper(int index, NotifyCallback callback, bool immediateNotify, delegate* managed<int, HalNativeNotifyCallback, void*, bool, int> register, delegate* managed<int, int, void> 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<int, HalNativeNotifyCallback, void*, bool, int> register, delegate* managed<int, int, void> 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();
}
}
64 changes: 64 additions & 0 deletions src/hal/Handles/SimCallbacks.cs
Original file line number Diff line number Diff line change
@@ -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<byte> name, HalValue value);

public delegate void BufferCallback(string name, Span<byte> buffer);
public delegate void BufferCallbackUtf8(ReadOnlySpan<byte> name, Span<byte> buffer);

public delegate void ConstBufferCallback(string name, ReadOnlySpan<byte> buffer);
public delegate void ConstBufferCallbackUtf8(ReadOnlySpan<byte> name, ReadOnlySpan<byte> 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<byte> 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<byte> 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<byte> n = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(name);
utf8Callback(n, new(buffer, (int)count));
}
}
}

0 comments on commit 0457cef

Please sign in to comment.