diff --git a/HSI_HexagonMI_EF3/.vs/HSI_Sevenocean_EF3/v15/Browse.VC.db b/HSI_HexagonMI_EF3/.vs/HSI_Sevenocean_EF3/v15/Browse.VC.db deleted file mode 100644 index 916bf4d..0000000 Binary files a/HSI_HexagonMI_EF3/.vs/HSI_Sevenocean_EF3/v15/Browse.VC.db and /dev/null differ diff --git a/SerialAssistant/.gitattributes b/SerialAssistant/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/SerialAssistant/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/SerialAssistant/.gitignore b/SerialAssistant/.gitignore new file mode 100644 index 0000000..0d6c45d --- /dev/null +++ b/SerialAssistant/.gitignore @@ -0,0 +1,211 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml diff --git a/SerialAssistant/README.md b/SerialAssistant/README.md new file mode 100644 index 0000000..68a66ee Binary files /dev/null and b/SerialAssistant/README.md differ diff --git a/SerialAssistant/WPFSerialAssistant.sln b/SerialAssistant/WPFSerialAssistant.sln new file mode 100644 index 0000000..8e44acd --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFSerialAssistant", "WPFSerialAssistant\WPFSerialAssistant.csproj", "{DA01B86D-5BC1-4863-BAAC-71B309B09CC0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA01B86D-5BC1-4863-BAAC-71B309B09CC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA01B86D-5BC1-4863-BAAC-71B309B09CC0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA01B86D-5BC1-4863-BAAC-71B309B09CC0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA01B86D-5BC1-4863-BAAC-71B309B09CC0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/SerialAssistant/WPFSerialAssistant/About.xaml b/SerialAssistant/WPFSerialAssistant/About.xaml new file mode 100644 index 0000000..89b7b29 --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/About.xaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + EF3串口调试助手 + + + WPF Serial Assistant + + + + + 本串口工具旨在配合EF3电路板完成光栅点缓存数据的解析,读取和保存工作 + 版本编号:Verison 0.1 + 更新日期:2022.10.08 + + + + + + + diff --git a/SerialAssistant/WPFSerialAssistant/About.xaml.cs b/SerialAssistant/WPFSerialAssistant/About.xaml.cs new file mode 100644 index 0000000..84fe003 --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/About.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +//using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace WPFSerialAssistant +{ + /// + /// About.xaml 的交互逻辑 + /// + public partial class About : Window + { + public About() + { + InitializeComponent(); + } + } +} diff --git a/SerialAssistant/WPFSerialAssistant/App.config b/SerialAssistant/WPFSerialAssistant/App.config new file mode 100644 index 0000000..e707b32 --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/SerialAssistant/WPFSerialAssistant/App.xaml b/SerialAssistant/WPFSerialAssistant/App.xaml new file mode 100644 index 0000000..526759c --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/SerialAssistant/WPFSerialAssistant/App.xaml.cs b/SerialAssistant/WPFSerialAssistant/App.xaml.cs new file mode 100644 index 0000000..8a624f2 --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +//using System.Threading.Tasks; +using System.Windows; + +namespace WPFSerialAssistant +{ + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application + { + } +} diff --git a/SerialAssistant/WPFSerialAssistant/Core.cs b/SerialAssistant/WPFSerialAssistant/Core.cs new file mode 100644 index 0000000..144a47c --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/Core.cs @@ -0,0 +1,392 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +//using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; + +namespace WPFSerialAssistant +{ + public partial class MainWindow : Window + { + /// + /// 核心初始化 + /// + private void InitCore() + { + // 加载配置信息 + LoadConfig(); + + // 其他模块初始化 + InitClockTimer(); + InitAutoSendDataTimer(); + InitSerialPort(); + + // 查找可以使用的端口号 + FindPorts(); + } + + #region 状态栏 + /// + /// 更新时间信息 + /// + private void UpdateTimeDate() + { + string timeDateString = ""; + DateTime now = DateTime.Now; + timeDateString = string.Format("{0}年{1}月{2}日 {3}:{4}:{5}", + now.Year, + now.Month.ToString("00"), + now.Day.ToString("00"), + now.Hour.ToString("00"), + now.Minute.ToString("00"), + now.Second.ToString("00")); + + timeDateTextBlock.Text = timeDateString; + } + + /// + /// 警告信息提示(一直提示) + /// + /// 提示信息 + private void Alert(string message) + { + // #FF68217A + statusBar.Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0x21, 0x2A)); + statusInfoTextBlock.Text = message; + } + + /// + /// 普通状态信息提示 + /// + /// 提示信息 + private void Information(string message) + { + if (serialPort.IsOpen) + { + // #FFCA5100 + statusBar.Background = new SolidColorBrush(Color.FromArgb(0xFF, 0xCA, 0x51, 0x00)); + } + else + { + // #FF007ACC + statusBar.Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x00, 0x7A, 0xCC)); + } + statusInfoTextBlock.Text = message; + } + + #endregion + + private void RecvDataBoxAppend(string textData) + { + if (showRecvDataCheckBox.IsChecked == true) + { + this.recvDataRichTextBox.AppendText(textData); + this.recvDataRichTextBox.ScrollToEnd(); + } + } + + private bool SendData() + { + string textToSend = sendDataTextBox.Text; + if (string.IsNullOrEmpty(textToSend)) + { + Alert("要发送的内容不能为空!"); + return false; + } + + if (autoSendEnableCheckBox.IsChecked == true) + { + return SerialPortWrite(textToSend, false); + } + else + { + return SerialPortWrite(textToSend); + } + } + + private void AutoSendData() + { + bool ret = SendData(); + + if (ret == false) + { + return; + } + + // 启动自动发送定时器 + StartAutoSendDataTimer(GetAutoSendDataInterval()); + + // 提示处于自动发送状态 + progressBar.Visibility = Visibility.Visible; + Information("串口自动发送数据中..."); + } + + private int GetAutoSendDataInterval() + { + int interval = 1000; + + if (int.TryParse(autoSendIntervalTextBox.Text.Trim(), out interval) == true) + { + string select = timeUnitComboBox.Text.Trim(); + + switch (select) + { + case "毫秒": + break; + case "秒钟": + interval *= 1000; + break; + case "分钟": + interval = interval * 60 * 1000; + break; + default: + break; + } + } + + return interval; + } + + #region 配置信息 + // + // 目前保存的配置信息如下: + // 1. 波特率 + // 2. 奇偶校验位 + // 3. 数据位 + // 4. 停止位 + // 5. 字节编码 + // 6. 发送区文本内容 + // 7. 自动发送时间间隔 + // 8. 窗口状态:最大化|高度+宽度 + // 9. 面板显示状态 + // 10. 接收数据模式 + // 11. 是否显示接收数据 + // 12. 发送数据模式 + // 13. 发送追加内容 + // + + /// + /// 保存配置信息 + /// + private void SaveConfig() + { + // 配置对象实例 + Configuration config = new Configuration(); + + // 保存波特率 + AddBaudRate(config); + + // 保存奇偶校验位 + config.Add("parity", parityComboBox.SelectedIndex); + + // 保存数据位 + config.Add("dataBits", dataBitsComboBox.SelectedIndex); + + // 保存停止位 + config.Add("stopBits", stopBitsComboBox.SelectedIndex); + + // 字节编码 + config.Add("encoding", encodingComboBox.SelectedIndex); + + // 保存发送区文本内容 + config.Add("sendDataTextBoxText", sendDataTextBox.Text); + + // 自动发送时间间隔 + config.Add("autoSendDataInterval", autoSendIntervalTextBox.Text); + config.Add("timeUnit", timeUnitComboBox.SelectedIndex); + + // 窗口状态信息 + config.Add("maxmized", this.WindowState == WindowState.Maximized); + config.Add("windowWidth", this.Width); + config.Add("windowHeight", this.Height); + config.Add("windowLeft", this.Left); + config.Add("windowTop", this.Top); + + // 面板显示状态 + config.Add("serialPortConfigPanelVisible", serialPortConfigPanel.Visibility == Visibility.Visible); + config.Add("autoSendConfigPanelVisible", autoSendConfigPanel.Visibility == Visibility.Visible); + config.Add("serialCommunicationConfigPanelVisible", serialCommunicationConfigPanel.Visibility == Visibility.Visible); + + // 保存接收模式 + config.Add("receiveMode", receiveMode); + config.Add("showReceiveData", showReceiveData); + + // 保存发送模式 + config.Add("sendMode", sendMode); + + // 保存发送追加 + config.Add("appendContent", appendContent); + + + // 保存配置信息到磁盘中 + Configuration.Save(config, @"Config\default.conf"); + } + + /// + /// 将波特率列表添加进去 + /// + /// + private void AddBaudRate(Configuration conf) + { + conf.Add("baudRate", baudRateComboBox.Text); + } + + /// + /// 加载配置信息 + /// + private bool LoadConfig() + { + Configuration config = Configuration.Read(@"Config\default.conf"); + + if (config == null) + { + return false; + } + + // 获取波特率 + string baudRateStr = config.GetString("baudRate"); + baudRateComboBox.Text = baudRateStr; + + // 获取奇偶校验位 + int parityIndex = config.GetInt("parity"); + parityComboBox.SelectedIndex = parityIndex; + + // 获取数据位 + int dataBitsIndex = config.GetInt("dataBits"); + dataBitsComboBox.SelectedIndex = dataBitsIndex; + + // 获取停止位 + int stopBitsIndex = config.GetInt("stopBits"); + stopBitsComboBox.SelectedIndex = stopBitsIndex; + + // 获取编码 + int encodingIndex = config.GetInt("encoding"); + encodingComboBox.SelectedIndex = encodingIndex; + + // 获取发送区内容 + string sendDataText = config.GetString("sendDataTextBoxText"); + sendDataTextBox.Text = sendDataText; + + // 获取自动发送数据时间间隔 + string interval = config.GetString("autoSendDataInterval"); + int timeUnitIndex = config.GetInt("timeUnit"); + autoSendIntervalTextBox.Text = interval; + timeUnitComboBox.SelectedIndex = timeUnitIndex; + + // 窗口状态 + if (config.GetBool("maxmized")) + { + this.WindowState = WindowState.Maximized; + } + double width = config.GetDouble("windowWidth"); + double height = config.GetDouble("windowHeight"); + double top = config.GetDouble("windowTop"); + double left = config.GetDouble("windowLeft"); + this.Width = width; + this.Height = height; + this.Top = top; + this.Left = left; + + // 面板显示状态 + if (config.GetBool("serialPortConfigPanelVisible")) + { + serialSettingViewMenuItem.IsChecked = true; + serialPortConfigPanel.Visibility = Visibility.Visible; + } + else + { + serialSettingViewMenuItem.IsChecked = false; + serialPortConfigPanel.Visibility = Visibility.Collapsed; + } + + if (config.GetBool("autoSendConfigPanelVisible")) + { + autoSendDataSettingViewMenuItem.IsChecked = true; + autoSendConfigPanel.Visibility = Visibility.Visible; + } + else + { + autoSendDataSettingViewMenuItem.IsChecked = false; + autoSendConfigPanel.Visibility = Visibility.Collapsed; + } + + if (config.GetBool("serialCommunicationConfigPanelVisible")) + { + serialCommunicationSettingViewMenuItem.IsChecked = true; + serialCommunicationConfigPanel.Visibility = Visibility.Visible; + } + else + { + serialCommunicationSettingViewMenuItem.IsChecked = false; + serialCommunicationConfigPanel.Visibility = Visibility.Collapsed; + } + + // 加载接收模式 + receiveMode = (ReceiveMode)config.GetInt("receiveMode"); + + switch (receiveMode) + { + case ReceiveMode.Character: + recvCharacterRadioButton.IsChecked = true; + break; + case ReceiveMode.Hex: + recvHexRadioButton.IsChecked = true; + break; + case ReceiveMode.Decimal: + recvDecRadioButton.IsChecked = true; + break; + case ReceiveMode.Octal: + recvOctRadioButton.IsChecked = true; + break; + case ReceiveMode.Binary: + recvBinRadioButton.IsChecked = true; + break; + default: + break; + } + + showReceiveData = config.GetBool("showReceiveData"); + showRecvDataCheckBox.IsChecked = showReceiveData; + + // 加载发送模式 + sendMode = (SendMode)config.GetInt("sendMode"); + + switch (sendMode) + { + case SendMode.Character: + sendCharacterRadioButton.IsChecked = true; + break; + case SendMode.Hex: + sendHexRadioButton.IsChecked = true; + break; + default: + break; + } + + //加载追加内容 + appendContent = config.GetString("appendContent"); + + switch (appendContent) + { + case "": + appendNoneRadioButton.IsChecked = true; + break; + case "\r": + appendReturnRadioButton.IsChecked = true; + break; + case "\n": + appednNewLineRadioButton.IsChecked = true; + break; + case "\r\n": + appendReturnNewLineRadioButton.IsChecked = true; + break; + default: + break; + } + return true; + } + #endregion + } +} diff --git a/SerialAssistant/WPFSerialAssistant/EventHandler.cs b/SerialAssistant/WPFSerialAssistant/EventHandler.cs new file mode 100644 index 0000000..eac33fb --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/EventHandler.cs @@ -0,0 +1,522 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; + +namespace WPFSerialAssistant +{ + public enum ReceiveMode + { + Character, //字符显示 + Hex, //十六进制 + Decimal, //十进制 + Octal, //八进制 + Binary //二进制 + } + + public enum SendMode + { + Character, //字符 + Hex //十六进制 + } + public partial class MainWindow : Window + { + #region Global + // 接收并显示的方式 + private ReceiveMode receiveMode = ReceiveMode.Character; + + // 发送的方式 + private SendMode sendMode = SendMode.Character; + + #endregion + + #region Event handler for menu items + private void saveSerialDataMenuItem_Click(object sender, RoutedEventArgs e) + { + + } + + private void saveConfigMenuItem_Click(object sender, RoutedEventArgs e) + { + SaveConfig(); + // 状态栏显示保存成功 + Information("配置信息保存成功。"); + } + + private void loadConfigMenuItem_Click(object sender, RoutedEventArgs e) + { + LoadConfig(); + // 状态栏显示加载成功 + Information("配置信息加载成功。"); + } + + private void exitMenuItem_Click(object sender, RoutedEventArgs e) + { + Close(); + } + + private void serialSettingViewMenuItem_Click(object sender, RoutedEventArgs e) + { + bool state = serialSettingViewMenuItem.IsChecked; + + if (state == false) + { + serialPortConfigPanel.Visibility = Visibility.Visible; + } + else + { + serialPortConfigPanel.Visibility = Visibility.Collapsed; + if (IsCompactViewMode()) + { + serialPortConfigPanel.Visibility = Visibility.Visible; + EnterCompactViewMode(); + } + } + + serialSettingViewMenuItem.IsChecked = !state; + } + + private void autoSendDataSettingViewMenuItem_Click(object sender, RoutedEventArgs e) + { + bool state = autoSendDataSettingViewMenuItem.IsChecked; + + if (state == false) + { + autoSendConfigPanel.Visibility = Visibility.Visible; + } + else + { + autoSendConfigPanel.Visibility = Visibility.Collapsed; + if (IsCompactViewMode()) + { + autoSendConfigPanel.Visibility = Visibility.Visible; + EnterCompactViewMode(); + } + } + + autoSendDataSettingViewMenuItem.IsChecked = !state; + } + + private void serialCommunicationSettingViewMenuItem_Click(object sender, RoutedEventArgs e) + { + bool state = serialCommunicationSettingViewMenuItem.IsChecked; + + if (state == false) + { + serialCommunicationConfigPanel.Visibility = Visibility.Visible; + } + else + { + serialCommunicationConfigPanel.Visibility = Visibility.Collapsed; + + if (IsCompactViewMode()) + { + serialCommunicationConfigPanel.Visibility = Visibility.Visible; + EnterCompactViewMode(); + } + } + + serialCommunicationSettingViewMenuItem.IsChecked = !state; + } + + private void compactViewMenuItem_Click(object sender, RoutedEventArgs e) + { + if (IsCompactViewMode()) + { + RestoreViewMode(); + } + else + { + EnterCompactViewMode(); + } + } + + private void aboutMenuItem_Click(object sender, RoutedEventArgs e) + { + WPFSerialAssistant.About about = new About(); + about.ShowDialog(); + } + + private void helpMenuItem_Click(object sender, RoutedEventArgs e) + { + + } + #endregion + + #region Event handler for buttons and so on. + private void openClosePortButton_Click(object sender, RoutedEventArgs e) + { + if (serialPort.IsOpen) + { + if (ClosePort()) + { + openClosePortButton.Content = "打开"; + } + } + else + { + if (OpenPort()) + { + openClosePortButton.Content = "关闭"; + } + } + } + + private void findPortButton_Click(object sender, RoutedEventArgs e) + { + FindPorts(); + } + + private void autoSendEnableCheckBox_Click(object sender, RoutedEventArgs e) + { + if (autoSendEnableCheckBox.IsChecked == true) + { + Information(string.Format("使能串口自动发送功能,发送间隔:{0} {1}。", autoSendIntervalTextBox.Text, timeUnitComboBox.Text.Trim())); + } + else + { + Information("禁用串口自动发送功能。"); + StopAutoSendDataTimer(); + progressBar.Visibility = Visibility.Collapsed; + } + } + + private void sendDataButton_Click(object sender, RoutedEventArgs e) + { + if (autoSendEnableCheckBox.IsChecked == true) + { + AutoSendData(); + } + else + { + SendData(); + } + } + + private void saveRecvDataButton_Click(object sender, RoutedEventArgs e) + { + SaveData(GetSaveDataPath()); + } + + private void clearRecvDataBoxButton_Click(object sender, RoutedEventArgs e) + { + recvDataRichTextBox.Document.Blocks.Clear(); + } + + private void recvModeButton_Checked(object sender, RoutedEventArgs e) + { + RadioButton rb = sender as RadioButton; + + if (recvDataRichTextBox == null) + { + return; + } + + if (rb != null) + { + // + // TO-DO: + // 可以将已经存在在文本框中的内容全部转换成指定形式显示,而不是简单地清空 + // + recvDataRichTextBox.Document.Blocks.Clear(); + + switch (rb.Tag.ToString()) + { + case "char": + receiveMode = ReceiveMode.Character; + Information("提示:字符显示模式。"); + break; + case "hex": + receiveMode = ReceiveMode.Hex; + Information("提示:十六进制显示模式。"); + break; + case "dec": + receiveMode = ReceiveMode.Decimal; + Information("提示:十进制显示模式。"); + break; + case "oct": + receiveMode = ReceiveMode.Octal; + Information("提示:八进制显示模式。"); + break; + case "bin": + receiveMode = ReceiveMode.Binary; + Information("提示:二进制显示模式。"); + break; + default: + break; + } + } + } + + private bool showReceiveData = true; + private void showRecvDataCheckBox_Click(object sender, RoutedEventArgs e) + { + showReceiveData = (bool)showRecvDataCheckBox.IsChecked; + } + + private void sendDataModeRadioButton_Click(object sender, RoutedEventArgs e) + { + RadioButton rb = sender as RadioButton; + + if (rb != null) + { + switch (rb.Tag.ToString()) + { + case "char": + sendMode = SendMode.Character; + Information("提示:发送字符文本。"); + // 将文本框中内容转换成char + sendDataTextBox.Text = Utilities.ToSpecifiedText(sendDataTextBox.Text, SendMode.Character, serialPort.Encoding); + break; + case "hex": + // 将文本框中的内容转换成hex + sendMode = SendMode.Hex; + Information("提示:发送十六进制。输入十六进制数据之间用空格隔开,如:1D 2A 38。"); + sendDataTextBox.Text = Utilities.ToSpecifiedText(sendDataTextBox.Text, SendMode.Hex, serialPort.Encoding); + break; + default: + break; + } + } + } + + private void manualInputRadioButton_Click(object sender, RoutedEventArgs e) + { + + } + + private void loadFileRadioButton_Click(object sender, RoutedEventArgs e) + { + + } + + private void clearSendDataTextBox_Click(object sender, RoutedEventArgs e) + { + sendDataTextBox.Clear(); + } + + private void appendRadioButton_Click(object sender, RoutedEventArgs e) + { + RadioButton rb = sender as RadioButton; + if (rb != null) + { + switch (rb.Tag.ToString()) + { + case "none": + appendContent = ""; + break; + case "return": + appendContent = "\r"; + break; + case "newline": + appendContent = "\n"; + break; + case "retnewline": + appendContent = "\r\n"; + break; + default: + break; + } + Information("发送追加:" + rb.Content.ToString()); + } + } + #endregion + + #region Event handler for timers + private void ClockTimer_Tick(object sender, EventArgs e) + { + UpdateTimeDate(); + } + + /// + /// + /// + /// + /// + private void AutoSendDataTimer_Tick(object sender, EventArgs e) + { + bool ret = false; + ret = SendData(); + + if (ret == false) + { + StopAutoSendDataTimer(); + } + } + + /// + /// 窗口关闭前拦截 + /// + /// + /// + private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + // 释放没有关闭的端口资源 + if (serialPort.IsOpen) + { + ClosePort(); + } + + // 提示是否需要保存配置到文件中 + if (MessageBox.Show("是否在退出前保存软件配置?", "小贴士", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) + { + SaveConfig(); + } + } + + /// + /// 捕获窗口按键。 + /// + /// + /// + private void Window_KeyDown(object sender, KeyEventArgs e) + { + // Ctrl+S保存数据 + if (e.Key == Key.S && e.KeyboardDevice.IsKeyDown(Key.LeftCtrl)) + { + SaveData(GetSaveDataPath()); + } + + // Ctrl+Enter 进入/退出简洁视图模式 + if (e.Key == Key.Enter && e.KeyboardDevice.IsKeyDown(Key.LeftCtrl)) + { + if (IsCompactViewMode()) + { + RestoreViewMode(); + } + else + { + EnterCompactViewMode(); + } + } + + // Enter发送数据 + if (e.Key == Key.Enter) + { + SendData(); + } + } + + #endregion + + #region EventHandler for serialPort + + // 数据接收缓冲区 + private List receiveBuffer = new List(); + + // 一个阈值,当接收的字节数大于这么多字节数之后,就将当前的buffer内容交由数据处理的线程 + // 分析。这里存在一个问题,假如最后一次传输之后,缓冲区并没有达到阈值字节数,那么可能就 + // 没法启动数据处理的线程将最后一次传输的数据处理了。这里应当设定某种策略来保证数据能够 + // 在尽可能短的时间内得到处理。 + private const int THRESH_VALUE = 128; + + private bool shouldClear = true; + + /// + /// 更新:采用一个缓冲区,当有数据到达时,把字节读取出来暂存到缓冲区中,缓冲区到达定值 + /// 时,在显示区显示数据即可。 + /// + /// + /// + private void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) + { + System.IO.Ports.SerialPort sp = sender as System.IO.Ports.SerialPort; + + if (sp != null) + { + // 临时缓冲区将保存串口缓冲区的所有数据 + int bytesToRead = sp.BytesToRead; + byte[] tempBuffer = new byte[bytesToRead]; + + // 将缓冲区所有字节读取出来 + sp.Read(tempBuffer, 0, bytesToRead); + + // 检查是否需要清空全局缓冲区先 + if (shouldClear) + { + receiveBuffer.Clear(); + shouldClear = false; + } + + // 暂存缓冲区字节到全局缓冲区中等待处理 + receiveBuffer.AddRange(tempBuffer); + + if (receiveBuffer.Count >= THRESH_VALUE) + { + //Dispatcher.Invoke(new Action(() => + //{ + // recvDataRichTextBox.AppendText("Process data.\n"); + //})); + // 进行数据处理,采用新的线程进行处理。 + Thread dataHandler = new Thread(new ParameterizedThreadStart(ReceivedDataHandler)); + dataHandler.Start(receiveBuffer); + } + + // 启动定时器,防止因为一直没有到达缓冲区字节阈值,而导致接收到的数据一直留存在缓冲区中无法处理。 + StartCheckTimer(); + + this.Dispatcher.Invoke(new Action(() => + { + if (autoSendEnableCheckBox.IsChecked == false) + { + Information(""); + } + dataRecvStatusBarItem.Visibility = Visibility.Visible; + })); + } + } + + #endregion + + #region 数据处理 + + private void CheckTimer_Tick(object sender, EventArgs e) + { + // 触发了就把定时器关掉,防止重复触发。 + StopCheckTimer(); + + // 只有没有到达阈值的情况下才会强制其启动新的线程处理缓冲区数据。 + if (receiveBuffer.Count < THRESH_VALUE) + { + //recvDataRichTextBox.AppendText("Timeout!\n"); + // 进行数据处理,采用新的线程进行处理。 + Thread dataHandler = new Thread(new ParameterizedThreadStart(ReceivedDataHandler)); + dataHandler.Start(receiveBuffer); + } + } + + + private void ReceivedDataHandler(object obj) + { + List recvBuffer = new List(); + recvBuffer.AddRange((List)obj); + + if (recvBuffer.Count == 0) + { + return; + } + + // 必须应当保证全局缓冲区的数据能够被完整地备份出来,这样才能进行进一步的处理。 + shouldClear = true; + + this.Dispatcher.Invoke(new Action(() => + { + if (showReceiveData) + { + // 根据显示模式显示接收到的字节. + recvDataRichTextBox.AppendText(Utilities.BytesToText(recvBuffer, receiveMode, serialPort.Encoding)); + recvDataRichTextBox.ScrollToEnd(); + } + + dataRecvStatusBarItem.Visibility = Visibility.Collapsed; + })); + + // TO-DO: + // 处理数据,比如解析指令等等 + } + #endregion + } +} diff --git a/SerialAssistant/WPFSerialAssistant/MainWindow.xaml b/SerialAssistant/WPFSerialAssistant/MainWindow.xaml new file mode 100644 index 0000000..1480b1a --- /dev/null +++ b/SerialAssistant/WPFSerialAssistant/MainWindow.xaml @@ -0,0 +1,749 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 欢迎使用串口助手! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1200 + 2400 + 4800 + 9600 + 19200 + 38400 + 115200 + 256000 + + + + + + + + + + + 无(None) + 偶校验(Even) + 奇校验(Odd) + 保留为0(Space) + 保留为1(Mark) + + + + + + + + + + + 8 + 7 + 6 + 5 + + + + + + + + + + + 1 + 1.5 + 2 + + + + + + + + + + + Default + ASCII + Unicode + UTF-8 + + + + + + + + + + + + + + + 主要功能: + + 1. 可自由显示、隐藏的设置面板 + 2. 简洁视图模式,专注于数据收发 + 3. 软件主要配置可保存并恢复 + + 快捷键提示: + + 1. Ctrl+S: 保存接收区数据 + 2. Ctrl+Enter: 进/退简洁视图模式 + 3. Enter: 发送数据 + + + + + + + + + + + + + + + + + + + + 单次锁存 + + + 定时锁存 + + + 1000 + 2000 + + + + 分频锁存 + + + 20 + 100 + + + + + + +