using DevExpress.Diagram.Core.Shapes; using DevExpress.XtraBars.Docking2010; using DevExpress.XtraEditors; using DevExpress.XtraEditors.Controls; using DevExpress.XtraGantt.Scheduling; using DevExpress.XtraGauges.Win; using DevExpress.XtraSpreadsheet.DocumentFormats.Xlsb; using Ips.CorAlgorithm; using Ips.Library.Basic; using Ips.Library.DxpLib; using Ips.Library.Entity; using Ips.Sps.Tools.Xdcs; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Windows.Forms; namespace Ips.Sps.Tools.TdmaCgs { public partial class TdmaCgMainCtrl : DevExpress.XtraEditors.XtraUserControl { public TdmaCgMainCtrl() { InitializeComponent(); File1ButtonEdit.SetFileOpen(filter: FileFilterString.Dat); File2ButtonEdit.SetFileOpen(filter: FileFilterString.Dat); FsButtonEdit.SetUnitText("M"); DtoCenterButtonEdit.SetUnitText("us", false); DtoRangeButtonEdit.SetUnitText("us", false); SnrButtonEdit.SetUnitText("dB", false); DfoRangeButtonEdit.SetUnitText("Hz", false); DtoCorrButtonEdit.SetUnitText("us", false); DfoCorrButtonEdit.SetUnitText("us", false); MinTimeLenButtonEdit.SetUnitText("s"); FileTimeDateEdit.UseTimeEdit(); gvMain.UseDefaultSettings(new GridViewDefaultSetting() { Editable = true, ShowRowNum = true }); } string vmfile = Path.Combine(SpsConst.VmFolder, "tdmacg.json"); TdmaCgViewModel vm; CancellationTokenSource cts; private void TdmaCgMainCtrl_Load(object sender, EventArgs e) { if (File.Exists(vmfile)) { vm = JsonSerializer.Deserialize(File.ReadAllText(vmfile)); } else { vm = new TdmaCgViewModel(); } vm.PropertyChanged += Vm_PropertyChanged; bsMain.DataSource = vm; } private void Vm_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) { case nameof(TdmaCgViewModel.File1): File1Changed(); break; case nameof(TdmaCgViewModel.FileTime): FileTimeChanged(); break; case nameof(TdmaCgViewModel.FileTimeLen): FileTimeLenChanged(); break; case nameof(TdmaCgViewModel.Fs): FsChanged(); break; } } bool isChanging; void File1Changed() { string fileName = vm.File1; if (fileName.IsNullOrWhitespace()) { vm.FileTime = DateTime.MinValue; return; } FileInfo fi = new FileInfo(fileName); if (!fi.Exists) return; var timeStr = fi.Name.Substring(0, 14); if (DateTime.TryParseExact(timeStr, "yyyyMMddHHmmss", CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime fileTime)) { vm.FileTime = fileTime; } if (vm.Fs > 1e-6) { vm.FileTimeLen = fi.Length / 4 / (vm.Fs * 1e6); } else if (vm.FileTimeLen > 1e-6) { vm.Fs = fi.Length / 4 / vm.FileTimeLen; } } void FileTimeChanged() { } void FileTimeLenChanged() { if (isChanging) return; if (vm.File1.IsNullOrWhitespace()) return; if (!File.Exists(vm.File1)) return; isChanging = true; try { FileInfo fi = new FileInfo(vm.File1); vm.Fs = fi.Length / 4 / vm.FileTimeLen / 1000000; } finally { isChanging = false; } } void FsChanged() { if (isChanging) return; if (vm.File1.IsNullOrWhitespace()) return; if (!File.Exists(vm.File1)) return; isChanging = true; try { FileInfo fi = new FileInfo(vm.File1); vm.FileTimeLen = fi.Length / 4 / (vm.Fs * 1e6); } finally { isChanging = false; } } private async void btnStart_Click(object sender, EventArgs e) { if (vm != null) { File.WriteAllText(vmfile, JsonSerializer.Serialize(vm)); } if (vm.WorkItems.Count == 0) return; if (ValidateModelState()) return; if (cts != null) cts.Dispose(); cts = new CancellationTokenSource(); btnStart.Enabled = false; btnStop.Enabled = true; try { var workList = gvMain.GetVisibleRows(); await ExecuteCsgjAsync(vm, workList); } catch (Exception ex) { ex.HandleCancelEx(err => { MsgHelper.ShowError(err.Message, err); }); } finally { btnStart.Enabled = true; btnStop.Enabled = false; } } async Task ExecuteCsgjAsync(TdmaCgViewModel vm, IEnumerable workList) { if (workList.Any() is false) { MsgHelper.ShowMsg("参估列表为空!"); return; } var startTime = vm.FileTime; var endTime = vm.FileTime.AddSeconds(vm.FileTimeLen); var corOption = new CorOptions() { Fs = (int)(vm.Fs * 1e6), DtoCenter = vm.DtoCenter, DtoRange = vm.DtoRange, Snr = vm.Snr, DfoRange = vm.DfoRange, DtoCorr = vm.DtoCorr, DfoCorr = vm.DfoCorr }; using var fr = new FileStream(vm.File1, FileMode.Open, FileAccess.Read); foreach (var workItem in workList) { var slotList = workItem.SlotList.Where(m => m.SlotTime >= startTime && m.SlotTime < endTime); if (slotList.IsNullOrEmpty()) continue; if (vm.MinTimeLen > 1e-6 && slotList.Sum(m => m.TimeLenNs) >= vm.MinTimeLen * 1e9) continue; var mainFile = Path.Combine(FolderConsts.Temp, GuidSeq.Instance.Create().ToString("N") + ".dat"); bool success = ExportMainFile(startTime, endTime, vm.File1, mainFile, slotList); if (!success || !File.Exists(mainFile)) { MsgHelper.ShowMsg("获取主星时隙文件失败!"); return; } try { ExeResult res; if (vm.CalcType == Library.Entity.CorCalcType.Cpu) { res = await CocUtil.Calc(mainFile, vm.File2, corOption, token: cts.Token); } else { res = await CogUtil.Calc(mainFile, vm.File2, corOption, token: cts.Token); } workItem.Dto = 0; workItem.Dfo = 0; workItem.Snr = 0; if (res.ExitCode == 0 && res.Result.Length > 0) { var xgfItem = res.Result[0]; workItem.Dto = xgfItem.Dto; workItem.Dfo = xgfItem.Dfo; workItem.Snr = xgfItem.Snr; workItem.Message = ""; } else { workItem.Message = res.ExitMsg; } workItem.UseTime = res.RunTimeMs * 1.0 / 1000; } catch (Exception ex) { workItem.UseTime = 0; workItem.Message = ex.Message; } finally { FileUtil.DeleteIfExists(mainFile); } } } public bool ExportMainFile(DateTime startTime, DateTime endTime, string infile, string outfile, IEnumerable slotList) { using var fr = new FileStream(infile, FileMode.Open, FileAccess.Read); using var fw = new FileStream(outfile, FileMode.OpenOrCreate, FileAccess.Write); foreach (var slotItem in slotList) { int slotStart = (int)Math.Floor((slotItem.SlotTime - startTime).TotalSeconds * vm.Fs * 1e6 + slotItem.SlotTimeNs * vm.Fs * 1e-3) * 4; int slotLen = (int)Math.Floor(slotItem.TimeLenNs * vm.Fs * 1e-3) * 4; fw.Seek(slotStart, SeekOrigin.Begin); byte[] buf = new byte[slotLen]; fr.Read(buf, 0, buf.Length); fw.Write(buf); } fw.Flush(); fw.Dispose(); return true; } private void btnStop_Click(object sender, EventArgs e) { cts?.Cancel(); } private async void grpCgList_CustomButtonClick(object sender, BaseButtonEventArgs e) { cts?.Dispose(); cts = new CancellationTokenSource(); btnStart.Enabled = false; btnStop.Enabled = true; try { string caption = e.Button.Properties.Caption; switch (caption) { case "导入时隙": await ImportSlotAsync(); break; } } catch (Exception ex) { ex.HandleCancelEx(err => { MsgHelper.ShowError(err.Message, err); }); } finally { btnStart.Enabled = true; btnStop.Enabled = false; } } async Task ImportSlotAsync() { string filenames = ToolDialog.OpenFile("", "导入时隙文件", mutiSelect: true, filter: FileFilterString.Txt); if (filenames.IsNullOrWhitespace()) return; vm.SlotFile = filenames; var allLines = Enumerable.Empty(); foreach (var file in filenames.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)) { var fileLines = await File.ReadAllLinesAsync(file, cts.Token); allLines = allLines.Concat(fileLines); } var query = from line in allLines let lineArr = line.Split(',', StringSplitOptions.TrimEntries) where line.IsNotNullOrWhitespace() && lineArr.Length >= 7 let tdmaSlot = new TdmaSlot() { SlotTime = DateTime.ParseExact(lineArr[0], "yyyyMMddHHmmss", CultureInfo.CurrentCulture), SlotTimeNs = (int)(long.Parse(lineArr[1]) % 1e9), TimeLenNs = long.Parse(lineArr[2]), FreqPoint = long.Parse(lineArr[3]), Rate = int.Parse(lineArr[4]), UserId = lineArr[5], MacAddr = lineArr[6] } group tdmaSlot by new { tdmaSlot.UserId, tdmaSlot.MacAddr, tdmaSlot.FreqPoint, tdmaSlot.Rate } into slotGrp select slotGrp; vm.WorkItems.Clear(); foreach (var item in query) { TdmaWorkItemViewModel tdItem = new TdmaWorkItemViewModel() { UserId = item.Key.UserId, MacAddr = item.Key.MacAddr, FreqPoint = item.Key.FreqPoint, Rate = item.Key.Rate }; foreach (var slotSrc in item.OrderBy(m => m.SlotTime)) { tdItem.SlotList.Add(new TdmaSlotViewModel() { SlotTime = slotSrc.SlotTime, SlotTimeNs = slotSrc.SlotTimeNs, TimeLenNs = slotSrc.TimeLenNs }); } vm.WorkItems.Add(tdItem); } } private void File1ButtonEdit_EditValueChanged(object sender, EventArgs e) { var arg = e as ChangingEventArgs; string fileName = arg?.NewValue?.ToString(); ; if (fileName.IsNullOrWhitespace()) { vm.FileTime = DateTime.MinValue; return; } FileInfo fi = new FileInfo(fileName); if (!fi.Exists) { MsgHelper.ShowError("文件不存在!"); return; } var timeStr = fi.Name.Substring(0, 14); if (DateTime.TryParseExact(timeStr, "yyyyMMddHHmmss", CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime fileTime)) { vm.FileTime = fileTime; } if (vm.Fs > 1e-6) { vm.FileTimeLen = fi.Length / 4 / (vm.Fs * 1e6); } else if (vm.FileTimeLen > 1e-6) { vm.Fs = fi.Length / 4 / vm.FileTimeLen; } } private bool ValidateModelState() { dxError.ClearErrors(); if (vm.File1.IsNullOrWhitespace()) { dxError.SetError(File1ButtonEdit, "请选择文件1"); } if (vm.File2.IsNullOrWhitespace()) { dxError.SetError(File2ButtonEdit, "请选择文件2"); } if (vm.Fs < 1e-6) { dxError.SetError(FsButtonEdit, "采样率不能为空!"); } if (vm.DtoRange < 1e-6) { dxError.SetError(DtoRangeButtonEdit, "时差范围必须大于0"); } if (vm.DfoRange < 1e-6) { dxError.SetError(DfoRangeButtonEdit, "频差范围必须大于0"); } if (vm.Snr < 1e-6) { dxError.SetError(SnrButtonEdit, "信噪必须大于0"); } return dxError.HasErrors; } private void gvMain_RowClick(object sender, DevExpress.XtraGrid.Views.Grid.RowClickEventArgs e) { if (e.Button == MouseButtons.Right) { popGrid.ShowPopup(e.Location); } } private async void btnMenuCg_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { var workList = gvMain.GetVisibleRows(); await ExecuteCsgjAsync(vm, workList); } private void btnExportSlotFile_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { var workList = gvMain.GetSelectRow(); if (workList.IsNullOrEmpty()) { MsgHelper.ShowMsg("请选择要导出的项"); return; } string outDir = ToolDialog.OpenFolder("时隙文件路径"); if (outDir.IsNullOrWhitespace()) return; DirectoryUtil.CreateIfNotExists(outDir); var startTime = vm.FileTime; var endTime = vm.FileTime.AddSeconds(vm.FileTimeLen); foreach (var workItem in workList) { var slotList = workItem.SlotList.Where(m => m.SlotTime >= startTime && m.SlotTime < endTime); if (slotList.IsNullOrEmpty()) continue; var outfile = $"{vm.FileTime:yyyyMMddHHmmss}_{workItem.FreqPoint}_{workItem.Rate}_{workItem.UserId}_{workItem.MacAddr}"; outfile = Path.Combine(outDir, outfile); ExportMainFile(startTime, endTime, vm.File1, outfile, slotList); } } } }