WPF项目实战布局--通用固件下载 C#

news/2024/5/17 13:16:46/文章来源:https://blog.csdn.net/chenhao0568/article/details/128027865

每个作品都是产品

C# WPF版效果:

 C# winForm版效果:

 

一.布局设计UI

1.主体:grid 2行 2列

00 下载按钮 20%      01进度条 80% (同时显示百分比)

10 11都是跨列 显示日志

2.细节:百分比与进度条Value绑定。下载按钮默认获得焦点回车就能点击。日志只读等。各控件Name命名等。百分比水平垂直居中等。

(&D)快捷方式设置不了?

我想百分比后加%,绑定时如何设置?我知道用程序设置。

<Window x:Class="WpfM20UpdateFW.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"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:local="clr-namespace:WpfM20UpdateFW"mc:Ignorable="d"Title="M20 Update Firmware V1.0" Height="450" Width="800" Closed="Window_Closed"><Grid><Grid ShowGridLines="false" MinWidth="20" FocusManager.FocusedElement="{Binding ElementName=download}"><Grid.RowDefinitions><RowDefinition  Height="0.2*"></RowDefinition><RowDefinition  Height="0.8*"></RowDefinition></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="0.2*"></ColumnDefinition><ColumnDefinition Width="0.8*"></ColumnDefinition></Grid.ColumnDefinitions><Button x:Name="download" Grid.Row="0" Grid.Column="0" Click="Button_Click" >Download FW</Button><ProgressBar x:Name="Progress"  Grid.Row="0" Grid.Column="1" /><Label Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding ElementName=Progress,Path=Value}" FontSize="48"/><TextBox x:Name="logText"  Grid.Row="1" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" AcceptsReturn="True" IsReadOnly="True" /></Grid></Grid>
</Window>

二、程序代码

1.生成各控件的方法 

2.协议(固件下载),与我协议一致,都通用。

07首包 4字节固件长度+32字节固件MD5大写字符串

08中间包 1024字节每包,分包,分成多个中间包,最后一包发剩下(不剩就不发)

09尾包 

协议框架:头1字节+APDU长度2字节+APDU内容+CRC16 2字节

APDU结构:FC +功能码一字节(07,08,09)+ 00 00 00 +DATA长度2字节+DATA内容

3.流程

开串口,准备数据等。

线程一  清响应 发送   等信号或超时      有信号且结果正确,继续发送。发送完成显结果关串口等。

线程二  接收响应 解析结果 发信号         持续接收。

4.附加功能

 首次选择文件后,后续 插拨设备自动批量下载。监听USB插拨。

拖放文件到界面。winForm版我做了。

5.其他数据转换等功能API

6.细节

退出应用,关闭线程,关闭串口。

再次点下载,变为停止。

日志写入文件。

下载成功或失败 日志区变为绿色或红色。

支持全屏。

using FT_Tools;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO.Ports;
using System.Management;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using static FT_Tools.MySerialPort;namespace WpfM20UpdateFW
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{private bool responseIsOK = false;private Stopwatch sw;private bool thread_isRunning = false;private Thread thread = null;public static string templatePathName = @""; //资源号或本地文件名private EventWaitHandle _waitHandle = new AutoResetEvent(false);public MainWindow(){InitializeComponent();//插入设备//Description = USB Composite Device//DeviceID = USB\VID_2C7C & PID_0901\5 & 352FD79 & 0 & 1WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);insertWatcher.EventArrived += (s, e) =>{                //Log("M20 Arrived");var instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];//var description = instance.Properties["Description"];//Log(description.Name + " = " + description.Value);var deviceId = instance.Properties["DeviceID"];//Log(deviceId.Name + " = " + deviceId.Value);if (deviceId.Value.ToString().Contains("VID_2C7C&PID_0901")){Log("M20 Arrived");if (templatePathName.Length > 0){thread = new Thread(new ThreadStart(ThreadDownload));thread.Start();}}};insertWatcher.Start();WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);removeWatcher.EventArrived += (s, e) =>{//Log("M20 Removed");var instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];//var description = instance.Properties["Description"];//Log(description.Name + " = " + description.Value);var deviceId = instance.Properties["DeviceID"];//Log(deviceId.Name + " = " + deviceId.Value);if (deviceId.Value.ToString().Contains("VID_2C7C&PID_0901")){Log("M20 Removed");}};removeWatcher.Start();}private SerialPort serialPort = new SerialPort();private void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e){if (serialPort.BytesToRead > 0){byte[] buffer = new byte[serialPort.BytesToRead];int length = serialPort.Read(buffer, 0, buffer.Length);responseIsOK=reponse_Check(buffer, length);_waitHandle.Set(); // 唤醒等待}}private void Button_Click(object sender, RoutedEventArgs e){           if (thread_isRunning){Window_Closed(null,null); logText.Text="";Log("Stop Download");//显示在最后}else{var openFileDialog = new Microsoft.Win32.OpenFileDialog(){Filter = "FW File|*.bin",Multiselect = false};var result = openFileDialog.ShowDialog();if (result==true){templatePathName = openFileDialog.FileName;thread = new Thread(new ThreadStart(ThreadDownload));thread.Start();}}}public void ThreadDownload(){if (thread_isRunning) { Log("There are unfinished tasks, please wait..."); return; }thread_isRunning = true;sw = new Stopwatch();//计时sw.Start();bool b = ThreadDownload2();///sw.Stop();Log((b ? "Download success---------------" : "Download fail ***************") + ".Time consumption:" + sw.ElapsedMilliseconds + "ms");Log(b);if (serialPort.IsOpen) { serialPort.Close(); }thread_isRunning = false;}public bool ThreadDownload2(){Log("FW File:" + templatePathName);byte[] fBuffer = MyAPI.readFile(Log, templatePathName);if (fBuffer == null || fBuffer.Length == 0) { Log("fBuffer is empty"); return false; }string md5 = MyAPI.ComputeMD5(fBuffer);Log("fBuffer Size:" + fBuffer.Length + " md5:" + md5);string md5_hex = "";foreach (byte b2 in md5.ToUpper()){md5_hex += (string.Format("{0:X2}", b2));}int packageLength = 1024;Dispatcher.Invoke((Action)(() => {//Progress.Maximum = fBuffer.Length / packageLength + 3;//Progress.Visibility = Visibility.Visible;Progress.Value = 0;logText.Background = System.Windows.SystemColors.ControlBrush;logText.Text = ""; //清空还原}));//right response:A5 00 02 90 00 A5 D9int quantity = ((fBuffer.Length % packageLength) == 0) ? (fBuffer.Length / packageLength) : (fBuffer.Length / packageLength + 1);//发送包数量if (!SendString("FC 07 00 00 00 " + String.Format("{0:X4} ", 4 + 32) + String.Format("{0:X8} ", fBuffer.Length) + md5_hex)) { return false; } //startint len = packageLength;for (int i = 0; i < fBuffer.Length / packageLength; i++){Dispatcher.Invoke((Action)(() => { Progress.Value = 100*i/(fBuffer.Length / packageLength+3); }));if (!SendString("FC 08 00 00 00 " + String.Format("{0:X4} ", len) + byteArrayConvertToHexStr(fBuffer, i * packageLength, len))) { return false; }}if ((fBuffer.Length % packageLength) != 0) //最后一包{len = fBuffer.Length % packageLength;if (!SendString("FC 08 00 00 00 " + String.Format("{0:X4} ", len) + byteArrayConvertToHexStr(fBuffer, fBuffer.Length - len, len))) { return false; }}if (!SendString("FC 09 00 00 00 0000")) { return false; } //end Dispatcher.Invoke((Action)(() => { Progress.Value = Progress.Maximum; }));return true;}public Boolean SendString(string strHex){strHex = strHex.Replace(" ", "");strHex = "5A " + String.Format("{0:X4} ", strHex.Length / 2) + strHex + " ";//加上框架头1+APDU长度2+APDU+CRC16strHex += Crc16(strHex);Byte[] package = hexConvertToByteArray(strHex);Log("send:" + strHex); if (!serialPort.IsOpen){Log("The serial port is not opened, and automatically try to open the serial port!");if (!uartOpen()) { return false; }}responseIsOK = false;_waitHandle.Reset();//Log("before send time consumption:" + sw.ElapsedMilliseconds + "ms");serialPort.Write(package, 0, package.Length);//向串口发送一包(18字节)的数据//Log("after send time consumption:" + sw.ElapsedMilliseconds + "ms");if (!_waitHandle.WaitOne(10000)) { Log("Wait timeout 10s"); return false; }// 等待通知//Log("response time consumption:" + sw.ElapsedMilliseconds+"ms");return responseIsOK;//return false;}public bool reponse_Check(byte[] buffer,int length){if (buffer == null) { Log("buffer is null"); return false; }Log("recv(" + length + "):" + byteArrayConvertToHexStr(buffer, 0, length)); if (length > 6 && buffer[0] == 0xA5 && Crc16(buffer, (ushort)(length - 2)) == (buffer[length - 2]) * 256 + buffer[length - 1]){if (buffer[length - 2 - 2] == 0x90 && buffer[length - 1 - 2] == 0x00){//Log("Response check OK");return true;}else{Log("Response XXXXXXXXXXXXXXXXXXXXXX fail\r\n"); return false;}}else { Log("Response protocol format error XXXXXXXXXXXXXXXXXXXXXX fail\r\n"); }return false;}public string GetComName(){string[] ports = SerialPort.GetPortNames();if (ports.Length < 1){Log("No serial port available");return null;} //getDevice();string[] strArr = GetHarewareInfo(HardwareEnum.Win32_PnPEntity, "Name");foreach (string s in strArr){//Quectel USB Serial - 1 Port(COM7)if (s.Contains("COM")){Log(s);              if (s.Contains("Quectel USB Serial-1")){//Log(s);string com = s.Replace("Quectel USB Serial-1 Port", "");com = com.Replace(" ", "");com = com.Replace(")", "");com = com.Replace("(", "");Log("Identified M20 serial port:" + com);return com;}}}Log("Serial port not found,TEST MODE,return " + ports[0]);return ports[0];Log("Serial port not found, please check whether the driver is installed, whether the cable is plugged in, and whether the power is on");return null;}public bool uartOpen(){try{string portName = GetComName();if (portName == null) { return false; }serialPort.PortName = portName;serialPort.BaudRate = 2000000;serialPort.DataReceived += SerialPort_DataReceived;//添加事件注册serialPort.Close(); //先关再开                             serialPort.Open();serialPort.DiscardOutBuffer();serialPort.DiscardInBuffer();//清空缓冲Log("Serial port has been opened " + serialPort.PortName + " " + serialPort.BaudRate);return true;}catch (Exception e){Log("The serial port has been occupied! " + serialPort.PortName + e.ToString() + "\r\n\r\n"); //+" " + e.ToString()}return false;}private void Log(string str){Dispatcher.BeginInvoke((Action)(() => { //异步// Dispatcher.Invoke((Action)(() => {      //同步MyLog.MyLog.WriteLogs(MyLog.MyLog.fileName, "", str);if (logText.Text.Length > 5000){logText.Text = logText.Text.Substring(logText.Text.Length - 100); //clear}logText.Text += str+"\r\n";}));}private void Log(bool b){Dispatcher.BeginInvoke((Action)(() => { //异步// Dispatcher.Invoke((Action)(() => {      //同步        if (b) { logText.Background = new SolidColorBrush(Colors.Green);  }else { logText.Background = new SolidColorBrush(Colors.Red); }}));}private void Window_Closed(object sender, EventArgs e){try{if (thread != null){thread_isRunning = false;thread.Abort(); //终止线程}if (serialPort.IsOpen){serialPort.Close();}}catch { }}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_36462.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ms10-046漏洞利用+bypassuac提权

目录 前期准备 漏洞利用 上传文件到目标主机 UAC介绍 使用bypassuac模块绕过uac进行提权。 关于钓鱼链接的拓展 前期准备 Win xp sp3关闭防火墙 实验前提 保证连通性&#xff0c;进行互ping 漏洞利用 进入msf查看需要利用的漏洞&#xff1a;ms10-046 search ms10-046 …

Metabase学习教程:视图-4

将数据可视化为直方图 学习何时使用直方图&#xff0c;以及元数据库如何使创建直方图更容易。 我们将逐步创建直方图&#xff0c;它是一种条形图&#xff0c;显示连续范围内的数据组。柱状图有助于深入了解人们可能购买的商品的数量、他们可能购买的价格范围&#xff0c;甚至…

Flutter高仿微信-第37篇-单聊-红包

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 详情请参考 Flutter高仿微信-第29篇-单聊 &#xff0c; 这里只是提取红包功能的…

极光笔记 | 用 WhatsApp 进行海外用户运营的 N 个理由

在出海热潮下&#xff0c;各大企业纷纷将国内业务拓展到海外。而在各大企业出海时不可避免地会面临与国内完全不同的数据合规、网络环境、软件生态等问题。在这种情况下&#xff0c;企业如何针对海外用户实现本土化、精细化和稳定高效的消息触达&#xff0c;如何和用户保持紧密…

Linux零基础从入门到精通,必学的55个指令合集【上篇】

Linux学习笔记 资料下载&#xff1a; 链接: https://pan.baidu.com/s/1UvwkJaEJO7W3sU5qkCgKzA?pwdfe2f提取码: fe2f 本篇文章主要适用0基础的读者&#xff0c;内容会比较通俗易懂&#xff0c;也会有详细的图解教程&#xff0c;以及运行后的返回结果。我本人在系统性的学习…

2023-2028年中国化工新材料行业发展前景与投资趋势分析报告

本报告由锐观咨询重磅推出&#xff0c;对中国化工新材料行业的发展现状、竞争格局及市场供需形势进行了具体分析&#xff0c;并从行业的政策环境、经济环境、社会环境及技术环境等方面分析行业面临的机遇及挑战。还重点分析了重点企业的经营现状及发展格局&#xff0c;并对未来…

【学习笔记20】JavaScript数据类型之间的区别

一、数据类型 基本数据类型复杂数据类型 (function; object; array)二、存储的区别 基本数据类型: 存储在栈内存中, 变量内部就是实际的值引用数据类型: 变量存储在栈内存中, 变量内部存储的是指向堆内存的地址(对象实际的值, 存储在堆内存中)三、赋值的区别 1. 基本数据类型: …

零基础上手unity VR开发【将项目安装到Oculus头套中】

&#x1f4cc;个人主页&#xff1a;个人主页 ​&#x1f9c0; 推荐专栏&#xff1a;Unity VR 开发成神之路 --【着重解决VR项目开发难&#xff0c;国内资料匮乏的问题。从零入门&#xff0c;一步一个脚印&#xff0c;带你搞定VR开发! &#x1f63b;&#x1f63b;】 &#x1f4d…

交互与前端16 Tabulator 表格实践4

说明 继续给表格来加一些小功能。 内容 1 分页 在表格初始化的地方加两行配置,表格就实现了分页 pagination:true, //enable.paginationSize:20, // this option can take any positive integer value2 超链接 这个需求的来源是,一些微服务需要注释,所以我写了很多文档…

ShareSDK for Flutter

前言 这是一个基于ShareSDK功能的扩展的Flutter插件。使用此插件能够帮助您在使用Flutter开发应用时,快速地实现社会化功能,例如第三方授权登录,获取用户信息以及社交平台的分享等功能。 Demo例子&#xff1a;https://github.com/MobClub/ShareSDK-For-Flutter 开始集成 引入…

m基于QPSK调制解调的无线图像传输matlab仿真,包括扩频解扩均衡等模块

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 软件无线电在无线通信领域被称为是自模拟通信过渡到数字通信之后的又一次革命&#xff0c;在军用和民用方面都有着广阔的应用。它是一种新的无线通信技术&#xff0c;基于通用的可编程的…

c++ 旅行商问题(动态规划)

目录一、旅行商问题简介旅行商问题问题概述问题由来二、基本思路三、实现1、状态压缩2、状态转移四、代码复杂度分析一、旅行商问题简介 旅行商问题 TSP&#xff0c;即旅行商问题&#xff0c;又称TSP问题&#xff08;Traveling Salesman Problem&#xff09;&#xff0c;是数学…

vxe-table 表格尾部小计列项再合计展示

公式&#xff1a;店员奖金item1item3item5item7 this.dyjj全局变量 this.tableDat 全局数组 1.求出尾部小计这一行的数据 columns.map((column, columnIndex) > { var aa XEUtils.sum(data, column.property) this.tableDat.push(aa) if (columnIndex 0) { return ‘小计…

Sentinel流控规则

Sentinel流控规则 1、基本介绍 资源名&#xff1a;唯一名称&#xff0c;默认请求路径(如&#xff1a;http://localhost:8089/testA) 针对来源&#xff1a;Sentinel可以针对调用者进行限流&#xff0c;填写微服务名&#xff0c;指定对哪个微服务进行限流 &#xff0c;默认defa…

[附源码]java毕业设计疫情背景下叮当买菜管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

ARM-A架构入门基础(一)预备知识

14天学习训练营导师课程&#xff1a;周贺贺《ARMv8/ARMv9架构-快速入门》 1. 背景 ARM全称&#xff1a; Advanced RISC Machines。 ARM处理器&#xff1a; 基于ARM公司设计的架构而研发的处理器&#xff0c;包含arm core和外设。ARM公司本身不生产处理器&#xff0c;只出售技…

前端开发——HTML5新增的客户端校验

1.使用校验属性执行校验 HTML5新增了表单的校验属性,如required、pattern等。 required:定义表单不能为空。属性值是required或者省略.pattern:定义表单满足正则表单式1.required属性 required属性用于不能为空。属性值是required或者省略. 代码如下&#xff1a; <form …

HDI激光钻孔和常见问题

随着电子产品不断升级&#xff0c;对pcb工艺也会越来越高。且由于结构空间原因&#xff0c;对pcb的体积也会越来越小。因此pcb的工艺会越来越复杂。 一&#xff0c;什么样的孔才会用激光设备&#xff1f; 很多工程师看到工艺能力的时候&#xff0c;上面写的最小孔0.1mm&#x…

在github上部署静态页面

使用github-page部署静态页面 需求 假如你辛辛苦苦写好了一个静态网页&#xff0c;很想要炫耀一下&#xff0c;让大家都可以通过公网访问看到我的网页。但是不想太麻烦&#xff0c;买服务器&#xff0c;安装软件&#xff0c;部署环境&#xff0c;配置域名&#xff0c;备案&…

HashSet和HashMap

目录 一、HashSet 1、HashSet简单介绍 2、HashSet的常用方法 3、HashSet保证元素不重复的原理 二、HashMap 1、HashMap简单介绍 2、HashMet的常用方法 3、使用LinkedHashMap集合保证元素添加顺序 三、HashSet和HashMap的区别和联系 1、区别 2、联系 一、HashSet 1、Has…