feat: 添加16个遥控通道
parent
ec5fb3f3ad
commit
4fd583d9f9
Binary file not shown.
|
@ -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<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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
namespace LoraGamepad.ViewModels
|
namespace LoraGamepad.ViewModels
|
||||||
{
|
{
|
||||||
|
|
||||||
public class MainWindowViewModel : ViewModelBase
|
public class MainWindowViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
|
|
||||||
public TProViewModel TProViewModels { get; }
|
public TProViewModel TProViewModels { get; }
|
||||||
|
|
||||||
public MainWindowViewModel()
|
public MainWindowViewModel()
|
||||||
|
|
|
@ -2,16 +2,41 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
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">
|
x:Class="LoraGamepad.Views.TProView">
|
||||||
<DockPanel>
|
<Grid RowDefinitions="60,*,40,2*">
|
||||||
<Button DockPanel.Dock="Bottom"
|
<Grid Grid.Row="0" Background="Blue" ColumnDefinitions="*,3*,*">
|
||||||
HorizontalAlignment="Center">
|
<Slider Grid.Column="0"/>
|
||||||
Add an item
|
<Button Grid.Column="2" Width="100" Height="40"/>
|
||||||
</Button>
|
</Grid>
|
||||||
<StackPanel>
|
<Grid Grid.Row="1" Background="Gray" ColumnDefinitions="2*,*,4*,*,2*">
|
||||||
<CheckBox Margin="4">Walk the dog</CheckBox>
|
<Button Grid.Column="0" Width="80" Height="60"/>
|
||||||
<CheckBox Margin="4">Buy some milk</CheckBox>
|
<Slider Grid.Column="1" Orientation="Vertical"/>
|
||||||
|
<Slider Grid.Column="3" Orientation="Vertical"/>
|
||||||
|
<Button Grid.Column="4" Width="80" Height="60"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="2" Background="Yellow">
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
<Button Width="40" Margin="10"/>
|
||||||
|
<Button Width="40" Margin="10"/>
|
||||||
|
<Button Width="40" Margin="10"/>
|
||||||
|
<Button Width="40" Margin="10"/>
|
||||||
|
<Button Width="40" Margin="10"/>
|
||||||
|
<Button Width="40" Margin="10"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DockPanel>
|
</Grid>
|
||||||
|
<Grid Grid.Row="3" Background="Green" ColumnDefinitions="*,2*,*">
|
||||||
|
<Grid Grid.Column="0">
|
||||||
|
<Slider VerticalAlignment="Center"/>
|
||||||
|
<Slider Orientation="Vertical" HorizontalAlignment="Center"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Column="1" Background="Purple">
|
||||||
|
<TextBox Text="Hello T-Pro!"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Column="2">
|
||||||
|
<Slider VerticalAlignment="Center"/>
|
||||||
|
<Slider Orientation="Vertical" HorizontalAlignment="Center"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
Loading…
Reference in New Issue