每个作品都是产品
C# WPF版效果:
C# winForm版效果:

00 下载按钮 20% 01进度条 80% (同时显示百分比)
10 11都是跨列 显示日志
我想百分比后加%,绑定时如何设置?我知道用程序设置。
- <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 FWButton>
- <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>
07首包 4字节固件长度+32字节固件MD5大写字符串
08中间包 1024字节每包,分包,分成多个中间包,最后一包发剩下(不剩就不发)
09尾包
协议框架:头1字节+APDU长度2字节+APDU内容+CRC16 2字节
APDU结构:FC +功能码一字节(07,08,09)+ 00 00 00 +DATA长度2字节+DATA内容
开串口,准备数据等。
线程一 清响应 发送 等信号或超时 有信号且结果正确,继续发送。发送完成显结果关串口等。
线程二 接收响应 解析结果 发信号 持续接收。
首次选择文件后,后续 插拨设备自动批量下载。监听USB插拨。
拖放文件到界面。winForm版我做了。
退出应用,关闭线程,关闭串口。
再次点下载,变为停止。
日志写入文件。
下载成功或失败 日志区变为绿色或红色。
支持全屏。
- 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
- {
- ///
- /// MainWindow.xaml 的交互逻辑
- ///
- 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 { }
- }
- }
- }