123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125 |
- using Microsoft.Win32;
- using MV485.db;
- using MV485.Dlg;
- using MV485.helper;
- using MV485.model;
- using MV485.util;
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.ComponentModel;
- using System.IO;
- using System.Linq;
- using System.Security.Cryptography;
- 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.Navigation;
- namespace MV485.uc
- {
- /// <summary>
- /// UCDeviceUpgrade.xaml 的交互逻辑
- /// </summary>
- public partial class UCDeviceUpgrade : UserControl, INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
- protected void OnPropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
- // "\n烧写固件时需认真核对烧写文件,错误的文件回导致设备无法启动。\n" +
- public const string _warnInfo = "注意:要先读取到当前设备的版本信息后,再进行固件升级或回滚操作。" +
- "\n固件升级时建议修改波特率为115200,升级时间可控制在2分钟左右,波特率为9600时升级时长会超过10分钟。";
- public int[] PageSizeOptions = new int[] { 10, 20, 50 };
- //private DeviceUpgrade _deviceUpgrade;
- //private Progress<string> _progress;
- private RWRunConfig _rwRunConfig;
- private static readonly string LogFilePath =
- Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Documents", "deviceUpgrade_log.txt");
-
- private List<LogEntry> _logEntries = new List<LogEntry>();
- public ObservableCollection<TUpgradeHis> _hisList { get; set; }
- private int _hisRecords;
- public int HisRecords
- {
- get => _hisRecords;
- set
- {
- if(_hisRecords != value)
- {
- _hisRecords = value;
- OnPropertyChanged(nameof(HisRecords));
- }
- }
- }
- private TUpgradeHis _selectedHis;
- public TUpgradeHis SelectedHis
- {
- get => _selectedHis;
- set
- {
- if(_selectedHis != value)
- {
- _selectedHis = value;
- OnPropertyChanged(nameof(SelectedHis));
- }
- }
- }
- public PageModel DetailPage { get; set; }
- private int _curPageSize;
- public int CurPageSize
- {
- get => _curPageSize;
- set
- {
- if (_curPageSize != value)
- {
- _curPageSize = value;
- OnPropertyChanged(nameof(CurPageSize));
- DetailPage.InitDefaulValue(CurPageSize);
- LoadHisList();
- ConfigManager.Instance.UpdateConfig(ConfigKey.PageSize, _curPageSize.ToString());
- }
- }
- }
- public UCDeviceUpgrade()
- {
- InitializeComponent();
- this.DataContext = this;
- _hisList = new ObservableCollection<TUpgradeHis>();
- dgUpgradHis.ItemsSource = _hisList;
- cmbPageSize.ItemsSource = PageSizeOptions;
- if (int.TryParse(ConfigManager.Instance.GetConfigValue(ConfigKey.PageSize, "20"), out int curPageSize))
- {
- _curPageSize = curPageSize;
- }
- else
- {
- _curPageSize = 20;
- }
- DetailPage = new PageModel()
- {
- PageSize = _curPageSize,
- PageNumber = 1
- };
- LoadHisList();
- InitLoadItemsAndView(); //加载数据项及初始化页面内容
- LoadConfigLog();
- _rwRunConfig = new RWRunConfig();
- _rwRunConfig.RWLog += (message) =>{
- AppendLog(message);
- };
- _rwRunConfig.SerialConnected += (blConnected, portName, baudrate, address) =>
- {
- };
- _rwRunConfig.SerialStatusChanged += (blStatusChanged, portName, baudrate, address) =>
- {
- };
- txtWarmInfo.Text = _warnInfo;
- }
- //读取并加载日志
- private void LoadConfigLog()
- {
- Dispatcher.BeginInvoke(new Action(() =>
- {
- LoadLogs();
- }));
- }
- private void LoadLogs()
- {
- if (!File.Exists(LogFilePath))
- return;
- _logEntries.Clear(); // 先清空已有的日志记录
- //var lines = File.ReadAllLines("config_log.txt");
- var lines = File.ReadAllLines(LogFilePath);
- foreach (var line in lines)
- {
- var parts = line.Split(new[] { " - " }, 2, StringSplitOptions.None);
- if (parts.Length == 2)
- {
- _logEntries.Add(new LogEntry { Time = parts[0], Message = parts[1] });
- }
- }
- // 更新 ListView
- lvLogs.ItemsSource = null;
- lvLogs.ItemsSource = _logEntries;
- // 滚动到最后一条
- if (_logEntries.Count > 0)
- {
- lvLogs.ScrollIntoView(_logEntries[_logEntries.Count - 1]);
- }
- }
- //初始化加载页面项
- private void InitLoadItemsAndView()
- {
- LoadSerialPorts();
- //与设备通信的参数
- cmbBaudrate.ItemsSource = SerialHelper.BaudRates;
- var baudrates = ConfigManager.Instance.GetConfigValue(ConfigKey.ConfigBaudrate, "9600");
- cmbBaudrate.SelectedValue = baudrates;
- cmbDevId.ItemsSource = Enumerable.Range(1, 247).ToList();
- var devId = ConfigManager.Instance.GetConfigValue(ConfigKey.ConfigDevId, "1");
- cmbDevId.Text = devId;
- //初始化读数栏视图
- InitDataView();
-
- var upgradeFile = ConfigManager.Instance.GetConfigValue(ConfigKey.UpgradeFile, "");
- txtNewFirewarePath.Text = upgradeFile;
- txtNewFireware.Text = "";
- if (File.Exists(upgradeFile))
- {
- string fileNameOnly = Path.GetFileName(upgradeFile);
- if(Tools.TryParseFirmwareName(fileNameOnly,out string version))
- {
- txtNewFireware.Text = version;
- }
- }
- }
- private void InitDataView()
- {
- txtDeviceSn.Text = "";
- txtOldFireware.Text = "";
- }
- //加载串口列表
- private void LoadSerialPorts()
- {
- Dispatcher.BeginInvoke(new Action(() =>
- {
- cmbPortNames.ItemsSource = SerialHelper.GetSerialPortsWithDetails();
- if (cmbPortNames.Items.Count > 0)
- cmbPortNames.SelectedIndex = 0;
- //是否使用-基本配置选择的端口(应该用)
- var portName = ConfigManager.Instance.GetConfigValue(ConfigKey.ConfigPortName, "");
- cmbPortNames.SelectedValue = portName;
- }));
- }
- private void btnRefreshPorts_Click(object sender, RoutedEventArgs e)
- {
- LoadSerialPorts();
- AppendLog("串口列表已刷新");
- }
- private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
- {
- double totalWidth = lvLogs.ActualWidth;
- double timeColumnWidth = 120; // 时间列固定宽度
- double minMessageWidth = 200; // 消息列的最小宽度
- double newMessageWidth = Math.Max(minMessageWidth, totalWidth - timeColumnWidth - 40); // 计算新宽度
- ((GridView)lvLogs.View).Columns[1].Width = newMessageWidth;
- }
- //加载历史数据
- private async void LoadHisList()
- {
- _hisList.Clear();
- try
- {
- var result = await Task.Run(() =>
- {
- return DBUpgradeHis.GetPagedUpgradeHis(DetailPage.PageNumber, DetailPage.PageSize);
- });
- HisRecords = result.Item1;
- DetailPage.PageCount = result.Item2;
- var detailList = result.Item3;
- int index = 0;
- foreach (var detail in detailList)
- {
- index++;
- detail.Index = index + ((DetailPage.PageNumber - 1) * DetailPage.PageSize);
- _hisList.Add(detail);
- }
- }
- catch(Exception ex)
- {
- MessageBox.Show(Application.Current.MainWindow,
- $"加载历史数据时发生错误:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
- }
- }
- private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
- {
- if (e.Text.All(char.IsDigit))
- {
- e.Handled = false; // 如果是数字,允许输入
- }
- else
- {
- // 如果当前输入的字符不是数字,并且是中文输入法的拼音或候选字,禁止输入
- e.Handled = true;
- }
- }
- //读取设备版本的相关信息
- private async void BtnReadFireware_Click(object sender, RoutedEventArgs e)
- {
- if (!GetSerialParameter(out string portName, out byte devId, out int baudrate))
- {
- return;
- }
- InitDataView();
- string titleInfo = "正在读取抄表器版本相关数据";
- WaitWindow waitWindow = new WaitWindow(titleInfo)
- {
- Owner = Application.Current.MainWindow,
- WindowStartupLocation = WindowStartupLocation.CenterOwner
- };
- waitWindow.Show();
- try
- {
- string deviceSn = "";
- string fireware ="";
- bool blRead = await Task.Run(() =>
- {
- return _rwRunConfig.ReadFireware(portName, baudrate, devId,out deviceSn,out fireware);
- });
- AppendLog($"读取抄表器版本相关数据{(blRead ? "成功" : "失败")}");
- if (blRead)
- {
- txtDeviceSn.Text = deviceSn;
- txtOldFireware.Text = fireware;
- }
- else
- {
- MessageBox.Show(Application.Current.MainWindow, _rwRunConfig.GetLastError(), "错误",
- MessageBoxButton.OK, MessageBoxImage.Error);
- }
- }
- catch { }
- finally
- {
- waitWindow.Close();
- }
- }
- private async void BtnDeviceUpgrade_Click(object sender, RoutedEventArgs e)
- {
- //先验证bin文件
- string binPath = txtNewFirewarePath.Text.Trim();
- if (!File.Exists(binPath)) return;
- bool blResult = BinInspector.Inspect(binPath);
- if (!blResult)
- {
- MessageBox.Show(Application.Current.MainWindow,
- $"固件镜像文件验证不通过", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
- return;
- }
- //判断串口参数是否正确
- if (!GetSerialParameter(out string portName, out byte devId, out int baudrate))
- {
- return;
- }
- //判断是否读取了deviceSn,设备的当前版本
- if(string.IsNullOrEmpty(txtDeviceSn.Text) || string.IsNullOrEmpty(txtOldFireware.Text))
- {
- MessageBox.Show(Application.Current.MainWindow,
- $"请先读取设备的当前版本", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
- return;
- }
- //判断新的版本是否存在
- if (string.IsNullOrEmpty(txtNewFireware.Text) || string.IsNullOrEmpty(txtNewFirewarePath.Text))
- {
- MessageBox.Show(Application.Current.MainWindow,
- $"请选择要写入的新固件版本", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
- return;
- }
- string filePath = txtNewFirewarePath.Text.Trim();
- //判断新的固件文件是否存在
- if (!File.Exists(filePath))
- {
- MessageBox.Show(Application.Current.MainWindow,
- "新固件版本文件不存在", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
- return;
- }
-
- //读取新固件的大小及数据的CRC32值
- //计算CRC32的值
- byte[] fileData = File.ReadAllBytes(filePath);
- uint fileLen = (uint)fileData.Length;
- if (fileLen > 1024 * 1024)
- {
- MessageBox.Show(Application.Current.MainWindow,
- "新固件版本文件大小不合理", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
- return;
- }
- uint fileCRC32 = CRC32Helper.Crc32(fileData, fileData.Length);
- AppendLog($"fileSize={fileLen},fileCRC32={fileCRC32}");
- //开始升级
- //1.先向设备写入(通知)升级包文件的长度及CRC32的值
- string titleInfo = "开始写入升级包的信息";
- WaitUpgradeWindow waitWindow = new WaitUpgradeWindow(titleInfo)
- {
- Owner = Application.Current.MainWindow,
- WindowStartupLocation = WindowStartupLocation.CenterOwner
- };
- waitWindow.Show();
- Application.Current.MainWindow.IsEnabled = false;
- try
- {
- //开始先设备写入文件信息
- bool blWriteInfo = await Task.Run(() =>
- {
- return _rwRunConfig.WrtieUpgradeInfo(portName, baudrate, devId, fileLen, fileCRC32);
- });
- if (!blWriteInfo)
- {
- MessageBox.Show(Application.Current.MainWindow, "向设备写入固件信息失败", "错误",
- MessageBoxButton.OK, MessageBoxImage.Error);
- return;
- }
- //记录开始升级的信息
- TUpgradeHis upgradeHis = new TUpgradeHis()
- {
- HisId = Guid.NewGuid().ToString().Replace("-", ""),
- DeviceSn = txtDeviceSn.Text,
- PortName = portName,
- BaudRate = baudrate,
- Address = devId,
- OldFireware = txtOldFireware.Text,
- UpgradeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
- NewFireware = txtNewFireware.Text,
- UpgradeResult = 0
- };
- await AddUpgradeItem(upgradeHis);
- //开始通信
- DeviceUpgrade deviceUpgrade = new DeviceUpgrade();
- Progress<string> progress = new Progress<string>(msg =>
- {
- AppendLog(msg);
- });
- string percentText = "";
- //$"已发送:{packNum}/{totalPacks}({(double)packNum / totalPacks:P1})";
- deviceUpgrade.OnProgress += (packNum, totalPacks) =>
- {
- waitWindow.Dispatcher.BeginInvoke(new Action(() =>
- {
- //percentText = $"已发送:{packNum}/{totalPacks}({(double)packNum / totalPacks:P1})";
- percentText = $"已下载:{(double)packNum / totalPacks:P1}";
- waitWindow.TitleInfo = percentText;
- //$"已发送{packNum}/{totalPacks}";
- }));
- //waitWindow.Dispatcher.InvokeAsync(() =>
- //{
- // waitWindow.TitleInfo = $"已发送{packNum}/{totalPacks}";
- //});
- };
- waitWindow.StopUpgrade += async () =>
- {
- deviceUpgrade.StopSendFile();
- upgradeHis.UpgradeResult = -1; //升级失败
- await UpdateUpgradeResult(upgradeHis);
- return;
- };
- bool blSend = await deviceUpgrade.StartSendFileAsync(progress, portName, baudrate, fileData);
- if (blSend)
- {
- upgradeHis.UpgradeResult = 1; //升级失败
- await UpdateUpgradeResult(upgradeHis);
- //提示继续等待设备重启,并验证升级是否成功
- //MessageBox.Show(Application.Current.MainWindow,"向设备写入新固件成功,")
- //MessageBoxResult result = MessageBox.Show("向设备写入新固件成功,设备即将重启。\n是否等待自动验证重启后的版本是否正确",
- // "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
- //if (result == MessageBoxResult.No) return;
- //继续等待失败是否成功
- titleInfo = $"向设备写入新固件成功,设备即将重启。\n正在等待验证重启后版本是否正确(1~2分钟)。";
- waitWindow.TitleInfo = titleInfo;
- //进入等待线程
- //开始及时
- string chDeviceSn="";
- string chFireware="";
- bool blWait = await Task.Run(() =>
- {
- int timeout = 2 * 60 * 1000; //等待2分钟
- while(timeout > 0)
- {
- //读取版本信息
- bool blReadFireware = _rwRunConfig.ReadFireware(portName, baudrate, devId, out chDeviceSn, out chFireware);
- if (blReadFireware) return true;
- Task.Delay(3000);
- timeout -= 1000;
- }
- return false;
- });
- if (blWait)
- {
- bool blSame = chDeviceSn.Equals(txtDeviceSn.Text) && chFireware.Equals(txtNewFireware.Text);
- MessageBox.Show(Application.Current.MainWindow, $"验证{(blSame ? "一致" : "不一致")}", "提示",
- MessageBoxButton.OK, MessageBoxImage.Information);
- }
- else
- {
- MessageBox.Show(Application.Current.MainWindow, "等待验证超时,请手动检查升级后的版本是否正确。", "警告",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- }
- }
- else
- {
- upgradeHis.UpgradeResult = -1; //升级失败
- await UpdateUpgradeResult(upgradeHis);
- MessageBox.Show(Application.Current.MainWindow, "向设备写入新固件时失败", "错误",
- MessageBoxButton.OK, MessageBoxImage.Error);
- }
- }
- catch { }
- finally
- {
- waitWindow.Close();
- Application.Current.MainWindow.IsEnabled = true;
- }
- }
- private async void BtnClearUpgradeHis_Click(object sender, RoutedEventArgs e)
- {
- //if (SelectedHis == null) return;
- MessageBoxResult result = MessageBox.Show("确定要清空所有数据吗?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
- if (result != MessageBoxResult.Yes) return;
- string titleInfo = "正在清空数据,请稍后...";
- WaitWindow waitWindow = new WaitWindow(titleInfo)
- {
- Owner = Application.Current.MainWindow,
- WindowStartupLocation = WindowStartupLocation.CenterOwner
- };
- waitWindow.Show();
- try
- {
- bool deleteSuccess = false;
- await Task.Run(() =>
- {
- deleteSuccess = DBUpgradeHis.DeleteUpgradeAllHis();
- });
- if (deleteSuccess)
- {
- DetailPage.InitDefaulValue();
- _hisList.Clear();
- HisRecords = 0;
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show(Application.Current.MainWindow, $"删除失败:{ex.Message}", "错误",
- MessageBoxButton.OK, MessageBoxImage.Error);
- }
- finally
- {
- waitWindow.Close();
- }
- }
- private void BtnRefreshUpgradeHis_Click(object sender, RoutedEventArgs e)
- {
- DetailPage.InitDefaulValue();
- LoadHisList();
- }
- private void BtnClearLog_Click(object sender, RoutedEventArgs e)
- {
- _logEntries.Clear();
- lvLogs.ItemsSource = null;
- File.WriteAllText(LogFilePath, "");
- AppendLog("日志已清空");
- }
- private void UserControl_Unloaded(object sender, RoutedEventArgs e)
- {
- }
- private void BtnDelUpgradeHis_Click(object sender, RoutedEventArgs e)
- {
- Button button = sender as Button;
- if (button == null) return;
- DataGridRow row = Tools.FindAncestor<DataGridRow>(button);
- if (row == null) return;
- //获取当前行绑定的数据项
- TUpgradeHis his = row.Item as TUpgradeHis;
- DeleteHis(his);
- }
- private void MiDeleteHis_Click(object sender, RoutedEventArgs e)
- {
- if (SelectedHis == null) return;
- DeleteHis(SelectedHis);
- }
- private void MenuItem_CopyMessage_Click(object sender, RoutedEventArgs e)
- {
- if (lvLogs.SelectedItem is LogEntry logEntry)
- {
- if (!LicenseMana.mIsLicensed)
- {
- MessageBox.Show(Application.Current.MainWindow, "软件未注册,不能使用此功能。", "提示",
- MessageBoxButton.OK, MessageBoxImage.Information);
- return;
- }
- Clipboard.SetText(logEntry.Message);
- }
- }
- private void CmbPortNames_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- }
- private void BtnDataFirstPage_Click(object sender, RoutedEventArgs e)
- {
- if (DetailPage.PageNumber > 1)
- {
- DetailPage.PageNumber = 1;
- LoadHisList();
- }
- }
- private void BtnDataPrePage_Click(object sender, RoutedEventArgs e)
- {
- if (DetailPage.PageNumber > 1)
- {
- DetailPage.PageNumber -= 1;
- LoadHisList();
- }
- }
- private void BtnDataNextPage_Click(object sender, RoutedEventArgs e)
- {
- if (DetailPage.PageNumber < DetailPage.PageCount)
- {
- DetailPage.PageNumber += 1;
- LoadHisList();
- }
- }
- private void BtnDataLastPage_Click(object sender, RoutedEventArgs e)
- {
- if (DetailPage.PageNumber < DetailPage.PageCount)
- {
- DetailPage.PageNumber = DetailPage.PageCount;
- LoadHisList();
- }
- }
- private void BtnDataSpeciPage_Click(object sender, RoutedEventArgs e)
- {
- if (!int.TryParse(txtDataPageNumber.Text, out int pageNumber))
- {
- return;
- }
- if (pageNumber != DetailPage.PageNumber &&
- pageNumber > 0 && pageNumber <= DetailPage.PageCount)
- {
- DetailPage.PageNumber = pageNumber;
- LoadHisList();
- }
- }
- private void AppendLog(string message)
- {
- Dispatcher.Invoke(() =>
- {
- var logEntry = new LogEntry { Time = DateTime.Now.ToString("HH:mm:ss.fff"), Message = message };
- _logEntries.Add(logEntry);
- lvLogs.ItemsSource = null;
- lvLogs.ItemsSource = _logEntries;
- lvLogs.ScrollIntoView(logEntry);
- // 确保 Logs 目录存在
- Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
- //File.AppendAllText("config_log.txt", $"{logEntry.Time} - {logEntry.Message}\n");
- // 追加日志
- File.AppendAllText(LogFilePath, $"{logEntry.Time} - {logEntry.Message}\n");
- });
- }
- //增加升级版本的历史
- private async Task AddUpgradeItem(TUpgradeHis his)
- {
- if (his == null) return;
- try
- {
- bool blInsert = await Task.Run(() =>
- {
- return DBUpgradeHis.InsertUpgradeHis(his);
- });
- if (!blInsert) return;
- await Dispatcher.InvokeAsync(() =>
- {
- _hisList.Insert(0, his);
- HisRecords++;
- DetailPage.PageCount = (int)Math.Ceiling(((double)HisRecords / DetailPage.PageSize));
- if (_hisList.Count > DetailPage.PageSize)
- {
- for (int i = _hisList.Count - 1; i >= DetailPage.PageSize; i--)
- {
- _hisList.Remove(_hisList[i]);
- }
- }
- for (int i = 0; i < _hisList.Count; i++)
- {
- _hisList[i].Index = i + 1;
- }
- });
- AppendLog("新增升级条目");
- }
- catch { }
- }
- private async Task UpdateUpgradeResult(TUpgradeHis his)
- {
- if (his == null) return;
- try
- {
- bool blUpdate = await Task.Run(() =>
- {
- return DBUpgradeHis.UpdateUpgradeResult(his);
- });
- AppendLog("更新条目的升级结果");
- }
- catch { }
- }
- private async Task UpdateUpgradeResultAndNewFireware(TUpgradeHis his)
- {
- if (his == null) return;
- try
- {
- bool blUpdate = await Task.Run(() =>
- {
- return DBUpgradeHis.UpdateUpgradeResultAndNewFrieware(his);
- });
- AppendLog("更新条目的升级结果");
- }
- catch { }
- }
- private async void BtnClearDataA_Click(object sender, RoutedEventArgs e)
- {
- TUpgradeHis his = new TUpgradeHis()
- {
- HisId = Guid.NewGuid().ToString().Replace("-", ""),
- DeviceSn = "12345678901",
- PortName = "COM6",
- BaudRate = 115200,
- Address = 1,
- OldFireware = "99.11.22",
- UpgradeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
- NewFireware = "99.11.23",
- UpgradeResult = 1
- };
- bool blInsert = await Task.Run(() =>
- {
- return DBUpgradeHis.InsertUpgradeHis(his);
- });
- if (blInsert)
- {
- _hisList.Insert(0, his);
- HisRecords++;
- DetailPage.PageCount = (int)Math.Ceiling(((double)HisRecords / DetailPage.PageSize));
- }
- if (_hisList.Count > DetailPage.PageSize)
- {
- for (int i = _hisList.Count - 1; i >= 10; i--)
- {
- _hisList.Remove(_hisList[i]);
- }
- }
- }
-
- private async void DeleteHis(TUpgradeHis his)
- {
- if (his == null) return;
- MessageBoxResult result = MessageBox.Show("确定要删除此条目吗?", "确认删除", MessageBoxButton.YesNo, MessageBoxImage.Question);
- if (result != MessageBoxResult.Yes) return;
- string titleInfo = "正在删除,请稍后...";
- WaitWindow waitWindow = new WaitWindow(titleInfo)
- {
- Owner = Application.Current.MainWindow,
- WindowStartupLocation = WindowStartupLocation.CenterOwner
- };
- waitWindow.Show();
- try
- {
- bool deleteSuccess = false;
- await Task.Run(() =>
- {
- deleteSuccess = DBUpgradeHis.DeleteUpgradeHisByHisId(his.HisId);
- });
- if (deleteSuccess)
- {
- //int index = _slaveList.IndexOf(slave);
- _hisList.Remove(his);
- //for (int i = index; i < _slaveList.Count; i++)
- //{
- // _slaveList[i].Index = i + 1;
- //}
- //改变它后面的Index
- SelectedHis = null;
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show(Application.Current.MainWindow, $"删除失败:{ex.Message}", "错误",
- MessageBoxButton.OK, MessageBoxImage.Error);
- }
- finally
- {
- waitWindow.Close();
- }
- }
- private bool GetSerialParameter(out string sPortName, out byte bDevId, out int iBaudrate)
- {
- sPortName = "";
- bDevId = 0;
- iBaudrate = 0;
- //串口号
- if (cmbPortNames.SelectedItem == null)
- {
- MessageBox.Show(Application.Current.MainWindow, "请选择串口", "提示",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- return false;
- }
- var portName = cmbPortNames.SelectedValue.ToString();
- ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigPortName, portName);
- //波特率
- if (cmbBaudrate.SelectedItem == null)
- {
- MessageBox.Show(Application.Current.MainWindow, "请选择波特率", "提示",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- return false;
- }
- var sBaudrate = cmbBaudrate.SelectedValue.ToString();
- ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigBaudrate, sBaudrate);
- if (!byte.TryParse(cmbDevId.Text, out byte devid) || devid < 0 || devid > 247)
- {
- MessageBox.Show(Application.Current.MainWindow, "请输入正确的设备地址", "提示",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- return false;
- }
- ConfigManager.Instance.UpdateConfig(ConfigKey.ConfigDevId, devid.ToString());
- int baudrate = int.Parse(sBaudrate);
- sPortName = portName;
- bDevId = devid;
- iBaudrate = baudrate;
- return true;
- }
-
- //选择新版本文件
- private void BtnSelNewFireware_Click(object sender, RoutedEventArgs e)
- {
- // 打开文件选择对话框
- var openFileDialog = new OpenFileDialog
- {
- Filter = "Firware Files (*.bin)|*.bin",
- Title = "选择新固件文件"
- };
- if (openFileDialog.ShowDialog() == true)
- {
- // 显示选择的文件名
- //txtExcelFile.Text = openFileDialog.FileName;
- //if (string.IsNullOrWhiteSpace(txtStandName.Text.Trim()))
- //{
- // txtStandName.Text = ThisApp.GetFileNameWithoutExtension(txtExcelFile.Text.Trim());
- //}
- string filePath = openFileDialog.FileName;
- string fileNameOnly = openFileDialog.SafeFileName;
- if(!Tools.TryParseFirmwareName(fileNameOnly,out string version))
- {
- MessageBox.Show(Application.Current.MainWindow, "请选择正确的固件文件", "提示",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- return;
- }
- if (!Tools.IsFileSizeValid(filePath))
- {
- MessageBox.Show(Application.Current.MainWindow, "固件文件的大小超出合理范围", "提示",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- return;
- }
- txtNewFirewarePath.Text = filePath;
- txtNewFireware.Text = version;
- ConfigManager.Instance.UpdateConfig(ConfigKey.UpgradeFile, filePath);
- //txtNewFireware.Tag = version; //存储版本
- }
- }
- private async void BtnDeviceRollback_Click(object sender, RoutedEventArgs e)
- {
- if (!GetSerialParameter(out string portName, out byte devId, out int baudrate))
- {
- return;
- }
- //判断是否读取了deviceSn,设备的当前版本
- if (string.IsNullOrEmpty(txtDeviceSn.Text) || string.IsNullOrEmpty(txtOldFireware.Text))
- {
- MessageBox.Show(Application.Current.MainWindow,
- $"请先读取设备的当前版本", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
- return;
- }
- //开始通过xModem协议读取照片
- string titleInfo = "正在通知设备回滚固件版本";
- WaitWindow waitWindow = new WaitWindow(titleInfo)
- {
- Owner = Application.Current.MainWindow,
- WindowStartupLocation = WindowStartupLocation.CenterOwner
- };
- waitWindow.Show();
- Application.Current.MainWindow.IsEnabled = false;
- try
- {
- bool blWrite = await Task.Run(() =>
- {
- return _rwRunConfig.WriteDeviceRollback(portName, baudrate, devId);
- });
- string msgInfo = $"通知回滚固件版本{(blWrite ? "成功" : "失败")}";
- AppendLog(msgInfo);
- if (!blWrite)
- {
- //msgInfo += "\n抄表器会重启,请等待1-2分钟,再尝试读取设备的版本信息。";
- MessageBox.Show(Application.Current.MainWindow, "通知回滚固件版本失败", "错误",
- MessageBoxButton.OK, MessageBoxImage.Error);
- return;
- }
- TUpgradeHis upgradeHis = new TUpgradeHis()
- {
- HisId = Guid.NewGuid().ToString().Replace("-", ""),
- DeviceSn = txtDeviceSn.Text,
- PortName = portName,
- BaudRate = baudrate,
- Address = devId,
- //OldFireware = txtOldFireware.Text,
- UpgradeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
- NewFireware = txtNewFireware.Text,
- UpgradeResult = 0
- };
- await AddUpgradeItem(upgradeHis);
- titleInfo = $"通知回滚固件版本成功,设备即将重启。\n正在等待验证重启后的版本(1~2分钟)。";
- waitWindow.TitleInfo = titleInfo;
- //进入等待线程
- //开始及时
- string chDeviceSn = "";
- string chFireware = "";
- bool blWait = await Task.Run(() =>
- {
- int timeout = 2 * 60 * 1000; //等待2分钟
- while (timeout > 0)
- {
- //读取版本信息
- bool blReadFireware = _rwRunConfig.ReadFireware(portName, baudrate, devId, out chDeviceSn, out chFireware);
- if (blReadFireware) return true;
- Task.Delay(3000);
- timeout -= 1000;
- }
- return false;
- });
- if (blWait)
- {
- upgradeHis.UpgradeResult = 2; //回滚成功标志
- upgradeHis.NewFireware = chFireware;
- await UpdateUpgradeResultAndNewFireware(upgradeHis);
- MessageBox.Show(Application.Current.MainWindow, $"回滚后的版本为{chFireware}", "提示",
- MessageBoxButton.OK, MessageBoxImage.Information);
- }
- else
- {
- MessageBox.Show(Application.Current.MainWindow, "等待验证超时,请手动检查回滚后的版本是否正确。", "警告",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- }
- }
- catch { }
- finally
- {
- waitWindow.Close();
- }
- }
- private void BtnVerity_Click(object sender, RoutedEventArgs e)
- {
- string filePath = txtNewFirewarePath.Text;
- if (!File.Exists(filePath)) return;
- byte[] data = File.ReadAllBytes(filePath);
- // Step 1: 查找 TLV Info 位置(TLV 区域从 data 末尾往前查找 0x07 0x69)
- int tlvStart = FindTlvStart(data);
- if (tlvStart == -1)
- {
- Console.WriteLine("未找到 TLV 区域");
- return;
- }
- ushort magic = BitConverter.ToUInt16(data, tlvStart);
- ushort totalTlvSize = BitConverter.ToUInt16(data, tlvStart + 2);
- Console.WriteLine($"TLV Magic: 0x{magic:X4}, Total TLV Size: {totalTlvSize}");
- if (magic != IMAGE_TLV_INFO_MAGIC)
- {
- Console.WriteLine("TLV magic 不匹配,非合法 bin 文件");
- return;
- }
- int hashOffset = -1;
- for (int offset = tlvStart + 4; offset < tlvStart + totalTlvSize;)
- {
- byte type = data[offset];
- ushort len = BitConverter.ToUInt16(data, offset + 2);
- if (type == 0x10) // IMAGE_TLV_SHA256
- {
- hashOffset = offset + 4;
- Console.WriteLine($"找到 SHA256 TLV,长度: {len} 字节");
- break;
- }
- offset += 4 + len;
- }
- if (hashOffset == -1)
- {
- Console.WriteLine("未找到 SHA256 TLV");
- return;
- }
- byte[] hashFromFile = data.Skip(hashOffset).Take(32).ToArray();
- // Step 2: 计算 SHA256(从 offset 0 到 TLV 起始位置)
- int hashRegionLength = tlvStart; // 不包含 TLV
- byte[] hashRegion = data.Take(hashRegionLength).ToArray();
- byte[] hashCalculated;
- using (SHA256 sha256 = SHA256.Create())
- {
- hashCalculated = sha256.ComputeHash(hashRegion);
- }
- Console.WriteLine("文件中保存的 SHA256:");
- Console.WriteLine(BitConverter.ToString(hashFromFile).Replace("-", ""));
- Console.WriteLine("计算得到的 SHA256:");
- Console.WriteLine(BitConverter.ToString(hashCalculated).Replace("-", ""));
- bool match = hashFromFile.SequenceEqual(hashCalculated);
- Console.WriteLine(match ? "✅ 验证通过,文件完整" : "❌ 哈希不一致,文件可能被修改");
- }
- const int IMAGE_HEADER_SIZE = 0x400; // MCUBoot header 1024 bytes
- const int IMAGE_TLV_INFO_MAGIC = 0x6907;
- static int FindTlvStart(byte[] data)
- {
- // TLV 的起始在文件尾部往前扫描 0x07 0x69(即 0x6907,低字节在前)
- for (int i = data.Length - 4; i >= IMAGE_HEADER_SIZE; i--)
- {
- if (data[i] == 0x07 && data[i + 1] == 0x69)
- {
- return i;
- }
- }
- return -1;
- }
- //---------------------------------------------------------
- }
- }
|