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

news2025/8/12 0:12:01

每个作品都是产品

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 & 1
            WqlEventQuery 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 D9

            int 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; } //start

            int 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+CRC16
            strHex += 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.coloradmin.cn/o/33681.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java EE初阶 — 计算机工作原理

文章目录1.操作系统2.操作系统的定位3.进程3.1 进程的基本了解3.2 操作系统内核是如何管理软件资源的3.3 PCB里描述了进程的哪些特征3.3.1 三个较为简单的特征3.3.2 进程的调度属性4.内存管理1.操作系统 操作系统是一个搞管理的软件。 对上要给软件提供稳定的运行环境。对下要…

Java面向对象之——继承

文章目录前言一、继承机制二、继承的语法三、父类成员访问&#x1f351;1、子类中访问父类的成员变量&#x1f351;2、子类中访问父类的成员方法四、super关键字五、子类构造方法六、super和this七、继承关系下的代码执行顺序八、访问限定修饰符protected九、Java继承方式十、f…

C#界面里Control.ImeMode 属性的使用

C#界面里Control.ImeMode 属性的使用 Control.ImeMode 属性是获取或设置控件的输入法编辑器 (IME) 模式。 输入法是一种特殊的程序,可以通过某种方式进行激活。 输入法程序总是在别的程序上面,因此它的运行是一种特殊的状态,所以需要特别处理。 因为电脑当时为了输入26个字…

第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京),签到题5题

文章目录A.Oops, Its Yesterday Twice MoreM.Windblume FestivalC.Klee in Solitary ConfinementH.CrystalflyD.Paimon Sorting补题链接&#xff1a;https://codeforces.com/gym/103470 A.Oops, It’s Yesterday Twice More Oops, It’s Yesterday Twice More Input file: st…

2020-RKT

2020-RKT&#xff1a;Relation-Aware Self-Attention for Knowledge Tracing 有代码&#xff1a;https://github.com/shalini1194/RKT 摘要 学生在解决练习的过程中获得技能&#xff0c;每一次这样的互动都对学生解决未来练习的能力有明显的影响。 这种影响表现为:1)互动中涉…

Transformer13~目标检测算法汇总

都到了13了 ~~ 还是基于这个的么办法 自从VIT横空出世以来&#xff0c;Transformer在CV界掀起了一场革新&#xff0c;各个上下游任务都得到了长足的进步&#xff0c;然后盘点一下基于Transformer的端到端目标检测算法&#xff01; 原始Tranformer检测器 DETR&#xff08;ECCV…

神经网络架构

神经网络架构 首先我们来看一张图&#xff0c;左边的是生物上的神经网络&#xff0c;右边的是数学版的神经网络 下面我们介绍在深度学习中神经网络的基本架构 整体架构包括层次结构&#xff0c;神经元&#xff0c;全连接&#xff0c;非线性四个部分 我们将针对这四个部分来进…

章节4 Linux操作系统基础知识

4.1-Linux系统结构 Linux系统结构 内核Shell文件系统应用程序 Linux操作系统内核 管理进程管理内存管理驱动管理文件和网络 … Linux Shell 接收用户的命令&#xff0c;经过转换&#xff0c;交给内核去执行 cat —> open() read() 简化操作安全 Linux Shell工具&am…

【docker学习记录】docker安装mysql、redis

目录 docker安装mysql docker安装redis docker安装mysql 1.下载镜像文件 $ sudo docker pull mysql:8.0.31 下载完成后查看一下镜像&#xff1a;sudo docker images 2.创建实例并启动 //mysql版本5 sudo docker run -p 3306:3306 --name mysql \ -v /mydata/mysql/log:/var…

uniapp的安装与基础

解释 由dcloud 公司开发的 多端融合框架 1次开发 多端运行 竞品&#xff1a;apiCloud &#xff0c;appCan &#xff0c;Codova 技术架构 Vue语法小程序的api Hybrid混合开发端 App端 - HTML - nvue&#xff08;原生view&#xff09; - native.js(js原生沟通的桥梁) - weex …

目前是大专学历如何快速提升到本科学历?学历提升有哪几种形式呢?

目前是大专学历如何快速提升到本科学历&#xff1f;学历提升有哪几种形式呢&#xff1f; 如今想要晋升和加薪&#xff0c;很多除了工作能力分级&#xff0c;另一个是文凭&#xff0c;许多企业和机构基本上是基于文凭来决定基本工资&#xff0c;所以想得到更好的待遇&#xff0c…

深度强化学习+金融投资的应用入门

原创文章第114篇&#xff0c;专注“个人成长与财富自由、世界运作的逻辑&#xff0c; AI量化投资”。 今天的核心工作是把强化学习环境整合进我们的AI量化平台中。 网上很多代码都把数据获取和预处理&#xff0c;都整合到强化学习的环境里&#xff0c;对于总体量化平台而言&am…

python搭建沙箱环境

python搭建沙箱环境 文章目录python搭建沙箱环境一&#xff0c;下载virtualenv模块1.1 在线状态的下载1.2 离线状态的下载二&#xff0c;创建沙箱环境&#xff08;虚拟环境&#xff09;三&#xff0c;激活以及退出沙箱环境一&#xff0c;下载virtualenv模块 1.1 在线状态的下载…

JAVA异常

目录JAVA异常1.初识异常2.异常的处理2.1 捕获异常的基本语法2.2 捕获异常2.3 finally的使用2.4 异常的执行流程2.5 抛出异常3.JAVA异常体系4.自定义异常类JAVA异常 1.初识异常 异常指的就是程序在 运行时 出现错误时通知调用者的一种机制. 我们在编写代码的过程中,遇到过许多…

模态贡献量在汽车NVH分析中的案例应用

作者 | 蓝枫 导读&#xff1a;模态贡献量分析是基于结构模态的频响分析&#xff0c;一般被用来分析诊断低频振动问题&#xff0c;如方向盘抖动、地板抖动以及整车振动等的低频NVH问题&#xff0c;也可以诊断中频问题&#xff0c;如NTF优化问题&#xff0c;但NTF优化一般用GPA…

[附源码]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…

171-178-Hadoop-源码

171-Hadoop-源码&#xff1a; 以了解有印象&#xff0c;动手debug为主。大致流程和思想。 RPC 通信原理解析 1&#xff09;需求&#xff1a; 模拟 RPC 的客户端、服务端、通信协议三者如何工作的 https://gitee.com/HaoZhouRS/bigdata-study-code/tree/master/big-data-stud…

视频转换软件哪个好?万兴优转-支持超过1000种格式转换和输出

想必大家都知道&#xff0c;视频的格式分为很多种&#xff0c;而且不同设备能够播放的视频格式也各不相同&#xff0c;就比如PC端和mac端&#xff0c;其就有很大的不兼容问题。在日常工作中&#xff0c;我们往往将一个视频发给了对方&#xff0c;但对方却因为设备的差异而无法直…

023.二叉树的最近公共祖先

题目链接&#xff1a; 236. 二叉树的最近公共祖先 大概思路&#xff1a; 题目要求&#xff1a; 给定一个二叉树, 找到该树中两个指定节点q&#xff0c;p的最近公共祖先x。&#xff08;q、p一定存在且值不同&#xff09; 最近公共祖先&#xff1a; 两个节点共同的祖先&…

为什么浏览器控制台(Console)运行JavaScript代码有时会出现“undefined”?

为什么浏览器控制台&#xff08;Console&#xff09;运行JavaScript代码有时会出现“undefined”&#xff1f; 浏览器“控制台”&#xff08;console&#xff09;使用简介 about:blank是打开浏览器空白页的命令——内置在浏览器中的命令&#xff0c;可以打开浏览器空白页&…