feat: 添加16个遥控通道

master
朱雅鸿 2022-11-06 15:59:20 +08:00
parent ec5fb3f3ad
commit 4fd583d9f9
4 changed files with 383 additions and 13 deletions

Binary file not shown.

View File

@ -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);
}
}
}

View File

@ -1,9 +1,7 @@
namespace LoraGamepad.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
public TProViewModel TProViewModels { get; }
public MainWindowViewModel()

View File

@ -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">
<DockPanel>
<Button DockPanel.Dock="Bottom"
HorizontalAlignment="Center">
Add an item
</Button>
<StackPanel>
<CheckBox Margin="4">Walk the dog</CheckBox>
<CheckBox Margin="4">Buy some milk</CheckBox>
<Grid RowDefinitions="60,*,40,2*">
<Grid Grid.Row="0" Background="Blue" ColumnDefinitions="*,3*,*">
<Slider Grid.Column="0"/>
<Button Grid.Column="2" Width="100" Height="40"/>
</Grid>
<Grid Grid.Row="1" Background="Gray" ColumnDefinitions="2*,*,4*,*,2*">
<Button Grid.Column="0" Width="80" Height="60"/>
<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>
</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>