diff --git a/LoraGamepad/Lib/serial_base-win.dll b/LoraGamepad/Lib/serial_base-win.dll new file mode 100644 index 0000000..4305ab4 Binary files /dev/null and b/LoraGamepad/Lib/serial_base-win.dll differ diff --git a/LoraGamepad/Models/SerialBase.cs b/LoraGamepad/Models/SerialBase.cs new file mode 100644 index 0000000..f7cfc1d --- /dev/null +++ b/LoraGamepad/Models/SerialBase.cs @@ -0,0 +1,347 @@ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + + +namespace Autolabor +{ + +[StructLayout(LayoutKind.Sequential)] + public struct SerialDevice + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string port; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string description; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string hardware_id; + public UInt16 vid; + public UInt16 pid; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string serial_num; + + } + public class SerialBaseException : Exception + { + public SerialBaseException(string message) + :base(message) + { + + } + } + + public class SerialBase + { + public static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) + { + + if (libraryName == "serial_base") + { + + if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + if (System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + + return NativeLibrary.Load("libserial_base-mac-arm64.dylib", assembly, searchPath); + + } + else + { + return NativeLibrary.Load("libserial_base-mac.dylib", assembly, searchPath); + } + + } + else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + if (System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + return NativeLibrary.Load("libserial_base-linux-arm64.so", assembly, searchPath); + } + else + { + return NativeLibrary.Load("libserial_base-linux.so", assembly, searchPath); + } + + } + else if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + return IntPtr.Zero; + } + else + { + return NativeLibrary.Load("serial_base-win.dll", assembly, searchPath); + } + + } + + } + return IntPtr.Zero; + } + + [DllImport("serial_base", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_enumerate_ports(IntPtr excep,IntPtr[] portlist ,ref int portsize); + + + [DllImport("serial_base",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_create(IntPtr excep,ref IntPtr serial,string port, int baudrate, int timeout); + + [DllImport("serial_base", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_open(IntPtr excep,IntPtr serial); + + [DllImport("serial_base", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_close(IntPtr excep,IntPtr serial); + + [DllImport("serial_base",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_is_open(IntPtr excep,IntPtr serial,ref bool opened); + + [DllImport("serial_base",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_write(IntPtr excep,IntPtr serial, IntPtr data,int size); + + [DllImport("serial_base",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + + private static extern bool al_serial_available(IntPtr excep,IntPtr serial, ref int avaiable_size); + + [DllImport("serial_base",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_read(IntPtr excep,IntPtr serial, int buffer_size,IntPtr data,ref int recev_size); + + [DllImport("serial_base",CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_readline(IntPtr excep,IntPtr serial, StringBuilder data,ref int recev_size); + + [DllImport("serial_base", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] + private static extern bool al_serial_delete(IntPtr excep,ref IntPtr serial); + + + private IntPtr _serialPtr; + + public string Port=string.Empty; + + public int Baudrate = 0; + + public int ReadTimeout = 80; + + + private const int PortInfoBufferSize = 32; + private const int ReadBufferSize = 1024; + private const int WriteBufferSize = 1024; + private const int ExceptionBufferSize = 256; //固定尺寸,不能修改 + + private IntPtr _readBuffer; + private IntPtr _writeBuffer; + private IntPtr _exceptionBuffer; + + private static bool dynamicLibLoaded = false; + + public SerialBase() + { + _serialPtr=IntPtr.Zero; + _readBuffer = Marshal.AllocHGlobal(ReadBufferSize); + _writeBuffer = Marshal.AllocHGlobal(WriteBufferSize); + _exceptionBuffer = Marshal.AllocHGlobal(ExceptionBufferSize); + + if (dynamicLibLoaded == false) + { + NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), SerialBase.DllImportResolver); + + dynamicLibLoaded = true; + + } + } + + public static List EnumeratePorts() + { + if (dynamicLibLoaded == false) + { + NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), SerialBase.DllImportResolver); + + dynamicLibLoaded = true; + } + + + IntPtr[] portinfoPtrs = new IntPtr[PortInfoBufferSize]; + + IntPtr _tmpExceptionBuffer = Marshal.AllocHGlobal(ExceptionBufferSize); + + List result = new List(); + + int copySize = 0; + + for (int i = 0; i < PortInfoBufferSize; i++) + { + portinfoPtrs[i] = Marshal.AllocHGlobal(Marshal.SizeOf()); + + } + + + bool success = al_serial_enumerate_ports(_tmpExceptionBuffer, portinfoPtrs, ref copySize); + + if (success == false) + { + for (int i = 0; i < PortInfoBufferSize; i++) + { + Marshal.FreeHGlobal(portinfoPtrs[i]); + } + + throw new SerialBaseException(_tmpExceptionBuffer.ToString()); + } + + for (int i = 0; i < copySize; i++) + { + + result.Add(Marshal.PtrToStructure(portinfoPtrs[i])); + + } + + for (int i = 0; i < PortInfoBufferSize; i++) + { + Marshal.FreeHGlobal(portinfoPtrs[i]); + } + + Marshal.FreeHGlobal(_tmpExceptionBuffer); + return result; + } + + + public void Open() + { + + if (_serialPtr == IntPtr.Zero) + { + + if (al_serial_create(_exceptionBuffer, ref _serialPtr, Port, Baudrate, ReadTimeout) == false) { + + throw new SerialBaseException(_exceptionBuffer.ToString()); + + } + } + else + { + if (al_serial_open(_exceptionBuffer,_serialPtr) == false) + { + throw new SerialBaseException(_exceptionBuffer.ToString()); + } + + } + + } + + public void Close() + { + + + if (_serialPtr == IntPtr.Zero) + { + return; + } + else + { + + if (al_serial_close(_exceptionBuffer,_serialPtr) == false) + { + throw new SerialBaseException(_exceptionBuffer.ToString()); + } + + + } + + } + + + public bool IsOpen() + { + + + if (_serialPtr == IntPtr.Zero) + { + return false; + } + + bool opened = false; + + + if (al_serial_is_open(_exceptionBuffer, _serialPtr,ref opened) == false) + { + throw new SerialBaseException(_exceptionBuffer.ToString()); + } + + return opened; + + } + + public void Write(byte[] data) + { + + if (_serialPtr == IntPtr.Zero) + { + throw new SerialBaseException("Serial is not open."); + } + + int sendCount = 0; + + // 分批发送数据 + while (sendCount < data.Length) { + + int needSend = (data.Length - sendCount) >= WriteBufferSize + ? WriteBufferSize + : (data.Length - sendCount); + + Marshal.Copy(data,sendCount,_writeBuffer, needSend); + + if (al_serial_write(_exceptionBuffer, _serialPtr, _writeBuffer,needSend) == false) + { + + throw new SerialBaseException(_exceptionBuffer.ToString()); + } + + sendCount += needSend; + + } + + } + + public byte[] Read() + { + + + if (_serialPtr == IntPtr.Zero) + { + throw new SerialBaseException("Serial is not open."); + } + + + int recvSize = 0; + + if (al_serial_read(_exceptionBuffer, _serialPtr,ReadBufferSize, _readBuffer,ref recvSize) == false) + { + throw new SerialBaseException(_exceptionBuffer.ToString()); + } + + + Byte[] recvData = new byte[recvSize]; + + Marshal.Copy(_readBuffer, recvData, 0, recvSize); + + return recvData; + + } + + + + + + ~SerialBase() { + al_serial_delete(_exceptionBuffer, ref _serialPtr); + _serialPtr=IntPtr.Zero; + Marshal.FreeHGlobal(_readBuffer); + Marshal.FreeHGlobal(_writeBuffer); + Marshal.FreeHGlobal(_exceptionBuffer); + + } + } +} diff --git a/LoraGamepad/ViewModels/MainWindowViewModel.cs b/LoraGamepad/ViewModels/MainWindowViewModel.cs index 98d056f..e233b7a 100644 --- a/LoraGamepad/ViewModels/MainWindowViewModel.cs +++ b/LoraGamepad/ViewModels/MainWindowViewModel.cs @@ -1,9 +1,7 @@ namespace LoraGamepad.ViewModels { - public class MainWindowViewModel : ViewModelBase { - public TProViewModel TProViewModels { get; } public MainWindowViewModel() diff --git a/LoraGamepad/Views/TProView.axaml b/LoraGamepad/Views/TProView.axaml index 8b6835e..724cdb9 100644 --- a/LoraGamepad/Views/TProView.axaml +++ b/LoraGamepad/Views/TProView.axaml @@ -2,16 +2,41 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="400" x:Class="LoraGamepad.Views.TProView"> - - - - Walk the dog - Buy some milk - - + + + +