当前位置: 首页 > news >正文

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

每个作品都是产品

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 { }
        }
    }
}

相关文章:

  • java EE初阶 — 计算机工作原理
  • 零时科技 || 分布式资本创始人4200万美金资产被盗分析及追踪工作
  • [附源码]java毕业设计医院预约挂号管理系统
  • 上游模式用于实验室用冷冻机压力和真空度的高精度控制
  • LinkedIn领英开发客户方法大全(篇一)
  • Spring中的ApplicationContext所体现出来的工厂模式
  • Navicat使用教程
  • 数据库 Apache Doris 展开了为期两个月的调研测试
  • 链接杂谈 CASPP
  • 面试:SurfaceView 和 TextureView
  • Scala、Spark的安装及配置
  • 【前端内容学习】vue的引用,下载,语法
  • Sentinel流控规则
  • mysql8.0以上修改密码-干货版
  • 图的拓扑序列
  • 六.方法与接口
  • 基于SpringBoot的篮球竞赛预约平台
  • 计算机毕业设计之java+ssm理发店会员管理系统
  • 基于JAVA的鲜花店商城平台【数据库设计、源码、开题报告】
  • openEuler之RPM软件包管理命令
  • 目标检测算法——YOLOv5/YOLOv7改进之结合特征提取网络RFBNet(涨点明显)
  • Spark中宽依赖、窄依赖、Job执行流程
  • R语言最优聚类数目k改进kmean聚类算法
  • 40 个机器学习面试问题(文末福利送书)
  • Springboot流浪动物管理系统p2326计算机毕业设计-课程设计-期末作业-毕设程序代做
  • Request和Response基础知识入门
  • 苍州苏融电锅炉厂产品_西宁燃气锅炉厂哪里有
  • 锅炉仪器有限公司厂家_那厂家生产取暖电锅炉
  • 间接式常压热水锅炉_58mw燃气热水锅炉安装预算