feat: 实现打开及关闭串口

master
朱雅鸿 2022-11-06 18:44:23 +08:00
parent 4fd583d9f9
commit d0ea556775
6 changed files with 332 additions and 7 deletions

View File

@ -9,4 +9,15 @@
<Application.Styles>
<FluentTheme Mode="Light"/>
</Application.Styles>
<Application.Resources>
<SolidColorBrush x:Key="BrightGrayBrush">#474445</SolidColorBrush>
<SolidColorBrush x:Key="MediumGrayBrush">#3b393a</SolidColorBrush>
<SolidColorBrush x:Key="ComboGrayBrush">#3a3a3a</SolidColorBrush>
<SolidColorBrush x:Key="DarkGrayBrush">#222121</SolidColorBrush>
<SolidColorBrush x:Key="DarkBlueBrush">#0865b1</SolidColorBrush>
<SolidColorBrush x:Key="BrightBlueBrush">#0f88eb</SolidColorBrush>
<SolidColorBrush x:Key="BrightRedBrush">#ef2244</SolidColorBrush>
<SolidColorBrush x:Key="DarkRedBrush">#c71e3a</SolidColorBrush>
</Application.Resources>
</Application>

View File

@ -25,6 +25,8 @@
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.18" />
<PackageReference Include="EventBinder.Avalonia" Version="2.5.0.1" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,45 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Autolabor;
namespace LoraGamepad.Models;
public class CBPortItem
{
public string PortName { get; set; }
public CBPortItem(string name)
{
PortName = name;
}
public static ObservableCollection<CBPortItem> GetPortList()
{
ObservableCollection<CBPortItem> portList = new ObservableCollection<CBPortItem>();
List<SerialDevice> infos = SerialPort.FindPorts();
foreach (var portInfo in infos)
{
portList.Add(new CBPortItem(portInfo.port));
}
return portList;
}
}
public class CBPortItemCompare : IEqualityComparer<CBPortItem>
{
public bool Equals(CBPortItem? x, CBPortItem? y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null)) return false;
if (ReferenceEquals(y, null)) return false;
if (x.GetType() != y.GetType()) return false;
return x.PortName == y.PortName;
}
public int GetHashCode(CBPortItem obj)
{
return obj.PortName.GetHashCode();
}
}

View File

@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Autolabor;
namespace LoraGamepad.Models;
/// <summary>
/// 串口驱动封装单例模式
/// </summary>
public class SerialPort
{
/// <summary>
/// 串口单例
/// </summary>
public static readonly SerialPort Me = new();
/// <summary>
/// 串口驱动基类
/// </summary>
private readonly SerialBase _serial = new();
private bool _isPortOpen = false;
private Action? _onWriteError;
/// <summary>
/// 串口是否打开属性
/// </summary>
public bool IsPortOpen => _isPortOpen;
/// <summary>
/// 搜索串口列表
/// </summary>
/// <returns></returns>
public static List<SerialDevice> FindPorts()
{
return SerialBase.EnumeratePorts();
}
public void LisenningPort(Action? onWriteError)
{
_onWriteError = onWriteError;
}
/// <summary>
/// 保护性构造函数
/// </summary>
private SerialPort() { }
/// <summary>
/// 打开串口
/// </summary>
/// <param name="port">串口名</param>
/// <param name="baudRate">波特率</param>
/// <param name="timeout">超时时间</param>
public void Open(string port,int baudRate,int timeout)
{
_serial.Port = port;
_serial.Baudrate = baudRate;
_serial.ReadTimeout = timeout;
try
{
_serial.Open();
_isPortOpen = true;
}
catch (SerialBaseException e)
{
Console.WriteLine(e);
}
}
/// <summary>
/// 串口发送
/// </summary>
/// <param name="data">Byte数据</param>
public void Write(byte[] data)
{
try
{
if (Me.IsPortOpen)
{
_serial.Write(data);
}
}
catch (SerialBaseException e)
{
_onWriteError?.Invoke();
Console.WriteLine(e);
}
}
/// <summary>
/// 读取串口
/// </summary>
/// <returns>Byte数组</returns>
public byte[] Read()
{
try
{
return _serial.Read();
}
catch (SerialBaseException e)
{
Console.WriteLine("My Line:" + e);
return Array.Empty<byte>();
}
}
public bool TryRead(out byte[] data)
{
if (_isPortOpen)
{
try
{
data = _serial.Read();
return true;
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
data = Array.Empty<byte>();
return false;
}
/// <summary>
/// 关闭串口
/// </summary>
public void Close()
{
try
{
_isPortOpen = false;
_serial.Close();
}
catch (SerialBaseException e)
{
Console.WriteLine(e);
}
}
}

View File

@ -1,9 +1,88 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using LoraGamepad.Models;
using ReactiveUI;
namespace LoraGamepad.ViewModels;
public class TProViewModel : ViewModelBase
{
private bool _isOpenPortButtonVisible = true;
private bool _isClosePortButtonVisible;
private ObservableCollection<CBPortItem> _portList = new();
public CBPortItem PortSelectItem { get; set; }
public ReactiveCommand<Unit, Unit> OpenPort { get; }
public ReactiveCommand<Unit, Unit> ClosePort { get; }
public TProViewModel()
{
PortList = CBPortItem.GetPortList();
OpenPort = ReactiveCommand.Create(PortOpenButtonClick);
ClosePort = ReactiveCommand.Create(PortCloseButtonClick);
}
/// <summary>
/// ComboBox串口列表绑定对象
/// </summary>
public ObservableCollection<CBPortItem> PortList
{
get => _portList;
set => this.RaiseAndSetIfChanged(ref _portList, value);
}
/// <summary>
/// 刷新串口列表事件处理函数
/// </summary>
public void OnPortListComboBoxPressed()
{
var newList = CBPortItem.GetPortList();
PortList.Except(newList,new CBPortItemCompare()).ToList().ForEach(a => { PortList.Remove(a); });
newList.Except(PortList, new CBPortItemCompare()).ToList().ForEach(a => { PortList.Add(a); });
newList.Except(PortList, new CBPortItemCompare()).ToList().ForEach(a => { PortList.Add(a); });
}
/// <summary>
/// 关闭串口按键可见性属性
/// </summary>
public bool IsClosePortButtonVisible
{
get => _isClosePortButtonVisible;
set => this.RaiseAndSetIfChanged(ref _isClosePortButtonVisible, value);
}
/// <summary>
/// 打开串口按键可见性属性
/// </summary>
public bool IsOpenPortButtonVisible
{
get => _isOpenPortButtonVisible;
set => this.RaiseAndSetIfChanged(ref _isOpenPortButtonVisible, value);
}
/// <summary>
/// 打开串口按键响应
/// </summary>
private void PortOpenButtonClick()
{
if (PortSelectItem.PortName == "") return;
SerialPort.Me.Open(PortSelectItem.PortName,420000,1000);
IsOpenPortButtonVisible = false;
IsClosePortButtonVisible = true;
}
/// <summary>
/// 关闭串口按键响应
/// </summary>
private void PortCloseButtonClick()
{
SerialPort.Me.Close();
IsOpenPortButtonVisible = true;
IsClosePortButtonVisible = false;
}
}

View File

@ -2,18 +2,63 @@
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"
xmlns:viewModels="clr-namespace:LoraGamepad.ViewModels"
xmlns:eventBinder="clr-namespace:EventBinder;assembly=EventBinder.Avalonia"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="400"
x:Class="LoraGamepad.Views.TProView">
<UserControl.DataContext>
<viewModels:TProViewModel/>
</UserControl.DataContext>
<!-- 样式设置 -->
<UserControl.Styles>
<Style Selector="Button.open">
<Setter Property="Background" Value="{DynamicResource DarkBlueBrush}"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="18"/>
</Style>
<Style Selector="Button.close">
<Setter Property="Background" Value="{DynamicResource DarkRedBrush}"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="18"/>
</Style>
<Style Selector="Button.open:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource BrightBlueBrush}"/>
<Setter Property="TextBlock.Foreground" Value="White"/>
</Style>
<Style Selector="Button.close:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource BrightRedBrush}"/>
<Setter Property="TextBlock.Foreground" Value="White"/>
</Style>
</UserControl.Styles>
<!-- 页面布局 -->
<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.Row="0" Background="Blue" ColumnDefinitions="*,2*,2*,*">
<Slider Grid.Column="0" Width="80" HorizontalAlignment="Center"/>
<ComboBox Grid.Column="1" SelectedIndex="0" VerticalAlignment="Center" Width="120" HorizontalAlignment="Right" Margin="10,0"
Items="{Binding PortList}"
SelectedItem="{Binding PortSelectItem}"
PointerPressed="{eventBinder:EventBinding OnPortListComboBoxPressed}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock FontSize="18" Foreground="White" Text="{Binding PortName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Grid.Column="2" Classes="open" Command="{Binding OpenPort}" IsVisible="{Binding IsOpenPortButtonVisible}"
HorizontalAlignment="Left" Margin="0,0,10,0" Content="打开串口" HorizontalContentAlignment="Center" Width="100"
Name="BtnPortOpen">
</Button>
<Button Grid.Column="2" Classes="close" Command="{Binding ClosePort}" IsVisible="{Binding IsClosePortButtonVisible}"
HorizontalAlignment="Left" Margin="0,0,10,0" Content="关闭串口" HorizontalContentAlignment="Center" Width="100"
Name="BtnPortClose">
</Button>
<Button Grid.Column="3" 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"/>
<Button Grid.Column="0" Width="80" Height="60" HorizontalAlignment="Center"/>
<Slider Grid.Column="1" Orientation="Vertical" HorizontalAlignment="Center"/>
<Slider Grid.Column="3" Orientation="Vertical" HorizontalAlignment="Center"/>
<Button Grid.Column="4" Width="80" Height="60" HorizontalAlignment="Center"/>
</Grid>
<Grid Grid.Row="2" Background="Yellow">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">