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 = 64; 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); } } }