TProPCMonitor/LoraGamepad/Models/SerialBase.cs

348 lines
11 KiB
C#

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<SerialDevice> EnumeratePorts()
{
if (dynamicLibLoaded == false)
{
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), SerialBase.DllImportResolver);
dynamicLibLoaded = true;
}
IntPtr[] portinfoPtrs = new IntPtr[PortInfoBufferSize];
IntPtr _tmpExceptionBuffer = Marshal.AllocHGlobal(ExceptionBufferSize);
List<SerialDevice> result = new List<SerialDevice>();
int copySize = 0;
for (int i = 0; i < PortInfoBufferSize; i++)
{
portinfoPtrs[i] = Marshal.AllocHGlobal(Marshal.SizeOf<SerialDevice>());
}
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<SerialDevice>(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);
}
}
}