TdmaCgMainCtrl.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. using DevExpress.Diagram.Core.Shapes;
  2. using DevExpress.XtraBars.Docking2010;
  3. using DevExpress.XtraEditors;
  4. using DevExpress.XtraEditors.Controls;
  5. using DevExpress.XtraGantt.Scheduling;
  6. using DevExpress.XtraGauges.Win;
  7. using DevExpress.XtraSpreadsheet.DocumentFormats.Xlsb;
  8. using Ips.CorAlgorithm;
  9. using Ips.Library.Basic;
  10. using Ips.Library.DxpLib;
  11. using Ips.Library.Entity;
  12. using Ips.Sps.Tools.Xdcs;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.ComponentModel;
  16. using System.Data;
  17. using System.Drawing;
  18. using System.Globalization;
  19. using System.IO;
  20. using System.Linq;
  21. using System.Text;
  22. using System.Text.Json;
  23. using System.Threading.Tasks;
  24. using System.Windows.Forms;
  25. namespace Ips.Sps.Tools.TdmaCgs
  26. {
  27. public partial class TdmaCgMainCtrl : DevExpress.XtraEditors.XtraUserControl
  28. {
  29. public TdmaCgMainCtrl()
  30. {
  31. InitializeComponent();
  32. File1ButtonEdit.SetFileOpen(filter: FileFilterString.Dat);
  33. File2ButtonEdit.SetFileOpen(filter: FileFilterString.Dat);
  34. FsButtonEdit.SetUnitText("M");
  35. DtoCenterButtonEdit.SetUnitText("us", false);
  36. DtoRangeButtonEdit.SetUnitText("us", false);
  37. SnrButtonEdit.SetUnitText("dB", false);
  38. DfoRangeButtonEdit.SetUnitText("Hz", false);
  39. DtoCorrButtonEdit.SetUnitText("us", false);
  40. DfoCorrButtonEdit.SetUnitText("us", false);
  41. MinTimeLenButtonEdit.SetUnitText("s");
  42. FileTimeDateEdit.UseTimeEdit();
  43. gvMain.UseDefaultSettings(new GridViewDefaultSetting()
  44. {
  45. Editable = true,
  46. ShowRowNum = true
  47. });
  48. }
  49. string vmfile = Path.Combine(SpsConst.VmFolder, "tdmacg.json");
  50. TdmaCgViewModel vm;
  51. CancellationTokenSource cts;
  52. private void TdmaCgMainCtrl_Load(object sender, EventArgs e)
  53. {
  54. if (File.Exists(vmfile))
  55. {
  56. vm = JsonSerializer.Deserialize<TdmaCgViewModel>(File.ReadAllText(vmfile));
  57. }
  58. else
  59. {
  60. vm = new TdmaCgViewModel();
  61. }
  62. vm.PropertyChanged += Vm_PropertyChanged;
  63. bsMain.DataSource = vm;
  64. }
  65. private void Vm_PropertyChanged(object sender, PropertyChangedEventArgs e)
  66. {
  67. switch (e.PropertyName)
  68. {
  69. case nameof(TdmaCgViewModel.File1):
  70. File1Changed();
  71. break;
  72. case nameof(TdmaCgViewModel.FileTime):
  73. FileTimeChanged();
  74. break;
  75. case nameof(TdmaCgViewModel.FileTimeLen):
  76. FileTimeLenChanged();
  77. break;
  78. case nameof(TdmaCgViewModel.Fs):
  79. FsChanged();
  80. break;
  81. }
  82. }
  83. bool isChanging;
  84. void File1Changed()
  85. {
  86. string fileName = vm.File1;
  87. if (fileName.IsNullOrWhitespace())
  88. {
  89. vm.FileTime = DateTime.MinValue;
  90. return;
  91. }
  92. FileInfo fi = new FileInfo(fileName);
  93. if (!fi.Exists) return;
  94. var timeStr = fi.Name.Substring(0, 14);
  95. if (DateTime.TryParseExact(timeStr, "yyyyMMddHHmmss", CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime fileTime))
  96. {
  97. vm.FileTime = fileTime;
  98. }
  99. if (vm.Fs > 1e-6)
  100. {
  101. vm.FileTimeLen = fi.Length / 4 / (vm.Fs * 1e6);
  102. }
  103. else if (vm.FileTimeLen > 1e-6)
  104. {
  105. vm.Fs = fi.Length / 4 / vm.FileTimeLen;
  106. }
  107. }
  108. void FileTimeChanged()
  109. {
  110. }
  111. void FileTimeLenChanged()
  112. {
  113. if (isChanging) return;
  114. if (vm.File1.IsNullOrWhitespace()) return;
  115. if (!File.Exists(vm.File1)) return;
  116. isChanging = true;
  117. try
  118. {
  119. FileInfo fi = new FileInfo(vm.File1);
  120. vm.Fs = fi.Length / 4 / vm.FileTimeLen / 1000000;
  121. }
  122. finally
  123. {
  124. isChanging = false;
  125. }
  126. }
  127. void FsChanged()
  128. {
  129. if (isChanging) return;
  130. if (vm.File1.IsNullOrWhitespace()) return;
  131. if (!File.Exists(vm.File1)) return;
  132. isChanging = true;
  133. try
  134. {
  135. FileInfo fi = new FileInfo(vm.File1);
  136. vm.FileTimeLen = fi.Length / 4 / (vm.Fs * 1e6);
  137. }
  138. finally
  139. {
  140. isChanging = false;
  141. }
  142. }
  143. private async void btnStart_Click(object sender, EventArgs e)
  144. {
  145. if (vm != null)
  146. {
  147. File.WriteAllText(vmfile, JsonSerializer.Serialize(vm));
  148. }
  149. if (vm.WorkItems.Count == 0) return;
  150. if (ValidateModelState()) return;
  151. if (cts != null) cts.Dispose();
  152. cts = new CancellationTokenSource();
  153. btnStart.Enabled = false;
  154. btnStop.Enabled = true;
  155. try
  156. {
  157. var workList = gvMain.GetVisibleRows<TdmaWorkItemViewModel>();
  158. await ExecuteCsgjAsync(vm, workList);
  159. }
  160. catch (Exception ex)
  161. {
  162. ex.HandleCancelEx(err =>
  163. {
  164. MsgHelper.ShowError(err.Message, err);
  165. });
  166. }
  167. finally
  168. {
  169. btnStart.Enabled = true;
  170. btnStop.Enabled = false;
  171. }
  172. }
  173. async Task ExecuteCsgjAsync(TdmaCgViewModel vm, IEnumerable<TdmaWorkItemViewModel> workList)
  174. {
  175. if (workList.Any() is false)
  176. {
  177. MsgHelper.ShowMsg("参估列表为空!");
  178. return;
  179. }
  180. var startTime = vm.FileTime;
  181. var endTime = vm.FileTime.AddSeconds(vm.FileTimeLen);
  182. var corOption = new CorOptions()
  183. {
  184. Fs = (int)(vm.Fs * 1e6),
  185. DtoCenter = vm.DtoCenter,
  186. DtoRange = vm.DtoRange,
  187. Snr = vm.Snr,
  188. DfoRange = vm.DfoRange,
  189. DtoCorr = vm.DtoCorr,
  190. DfoCorr = vm.DfoCorr
  191. };
  192. using var fr = new FileStream(vm.File1, FileMode.Open, FileAccess.Read);
  193. foreach (var workItem in workList)
  194. {
  195. var slotList = workItem.SlotList.Where(m => m.SlotTime >= startTime && m.SlotTime < endTime);
  196. if (slotList.IsNullOrEmpty()) continue;
  197. if (vm.MinTimeLen > 1e-6 && slotList.Sum(m => m.TimeLenNs) >= vm.MinTimeLen * 1e9) continue;
  198. var mainFile = Path.Combine(FolderConsts.Temp, GuidSeq.Instance.Create().ToString("N") + ".dat");
  199. bool success = ExportMainFile(startTime, endTime, vm.File1, mainFile, slotList);
  200. if (!success || !File.Exists(mainFile))
  201. {
  202. MsgHelper.ShowMsg("获取主星时隙文件失败!");
  203. return;
  204. }
  205. try
  206. {
  207. ExeResult<CorResult[]> res;
  208. if (vm.CalcType == Library.Entity.CorCalcType.Cpu)
  209. {
  210. res = await CocUtil.Calc(mainFile, vm.File2, corOption, token: cts.Token);
  211. }
  212. else
  213. {
  214. res = await CogUtil.Calc(mainFile, vm.File2, corOption, token: cts.Token);
  215. }
  216. workItem.Dto = 0;
  217. workItem.Dfo = 0;
  218. workItem.Snr = 0;
  219. if (res.ExitCode == 0 && res.Result.Length > 0)
  220. {
  221. var xgfItem = res.Result[0];
  222. workItem.Dto = xgfItem.Dto;
  223. workItem.Dfo = xgfItem.Dfo;
  224. workItem.Snr = xgfItem.Snr;
  225. workItem.Message = "";
  226. }
  227. else
  228. {
  229. workItem.Message = res.ExitMsg;
  230. }
  231. workItem.UseTime = res.RunTimeMs * 1.0 / 1000;
  232. }
  233. catch (Exception ex)
  234. {
  235. workItem.UseTime = 0;
  236. workItem.Message = ex.Message;
  237. }
  238. finally
  239. {
  240. FileUtil.DeleteIfExists(mainFile);
  241. }
  242. }
  243. }
  244. public bool ExportMainFile(DateTime startTime, DateTime endTime, string infile, string outfile, IEnumerable<TdmaSlotViewModel> slotList)
  245. {
  246. using var fr = new FileStream(infile, FileMode.Open, FileAccess.Read);
  247. using var fw = new FileStream(outfile, FileMode.OpenOrCreate, FileAccess.Write);
  248. foreach (var slotItem in slotList)
  249. {
  250. int slotStart = (int)Math.Floor((slotItem.SlotTime - startTime).TotalSeconds * vm.Fs * 1e6 + slotItem.SlotTimeNs * vm.Fs * 1e-3) * 4;
  251. int slotLen = (int)Math.Floor(slotItem.TimeLenNs * vm.Fs * 1e-3) * 4;
  252. fw.Seek(slotStart, SeekOrigin.Begin);
  253. byte[] buf = new byte[slotLen];
  254. fr.Read(buf, 0, buf.Length);
  255. fw.Write(buf);
  256. }
  257. fw.Flush();
  258. fw.Dispose();
  259. return true;
  260. }
  261. private void btnStop_Click(object sender, EventArgs e)
  262. {
  263. cts?.Cancel();
  264. }
  265. private async void grpCgList_CustomButtonClick(object sender, BaseButtonEventArgs e)
  266. {
  267. cts?.Dispose();
  268. cts = new CancellationTokenSource();
  269. btnStart.Enabled = false;
  270. btnStop.Enabled = true;
  271. try
  272. {
  273. string caption = e.Button.Properties.Caption;
  274. switch (caption)
  275. {
  276. case "导入时隙":
  277. await ImportSlotAsync();
  278. break;
  279. }
  280. }
  281. catch (Exception ex)
  282. {
  283. ex.HandleCancelEx(err =>
  284. {
  285. MsgHelper.ShowError(err.Message, err);
  286. });
  287. }
  288. finally
  289. {
  290. btnStart.Enabled = true;
  291. btnStop.Enabled = false;
  292. }
  293. }
  294. async Task ImportSlotAsync()
  295. {
  296. string filenames = ToolDialog.OpenFile("", "导入时隙文件", mutiSelect: true, filter: FileFilterString.Txt);
  297. if (filenames.IsNullOrWhitespace()) return;
  298. vm.SlotFile = filenames;
  299. var allLines = Enumerable.Empty<string>();
  300. foreach (var file in filenames.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries))
  301. {
  302. var fileLines = await File.ReadAllLinesAsync(file, cts.Token);
  303. allLines = allLines.Concat(fileLines);
  304. }
  305. var query = from line in allLines
  306. let lineArr = line.Split(',', StringSplitOptions.TrimEntries)
  307. where line.IsNotNullOrWhitespace() && lineArr.Length >= 7
  308. let tdmaSlot = new TdmaSlot()
  309. {
  310. SlotTime = DateTime.ParseExact(lineArr[0], "yyyyMMddHHmmss", CultureInfo.CurrentCulture),
  311. SlotTimeNs = (int)(long.Parse(lineArr[1]) % 1e9),
  312. TimeLenNs = long.Parse(lineArr[2]),
  313. FreqPoint = long.Parse(lineArr[3]),
  314. Rate = int.Parse(lineArr[4]),
  315. UserId = lineArr[5],
  316. MacAddr = lineArr[6]
  317. }
  318. group tdmaSlot by new { tdmaSlot.UserId, tdmaSlot.MacAddr, tdmaSlot.FreqPoint, tdmaSlot.Rate } into slotGrp
  319. select slotGrp;
  320. vm.WorkItems.Clear();
  321. foreach (var item in query)
  322. {
  323. TdmaWorkItemViewModel tdItem = new TdmaWorkItemViewModel()
  324. {
  325. UserId = item.Key.UserId,
  326. MacAddr = item.Key.MacAddr,
  327. FreqPoint = item.Key.FreqPoint,
  328. Rate = item.Key.Rate
  329. };
  330. foreach (var slotSrc in item.OrderBy(m => m.SlotTime))
  331. {
  332. tdItem.SlotList.Add(new TdmaSlotViewModel()
  333. {
  334. SlotTime = slotSrc.SlotTime,
  335. SlotTimeNs = slotSrc.SlotTimeNs,
  336. TimeLenNs = slotSrc.TimeLenNs
  337. });
  338. }
  339. vm.WorkItems.Add(tdItem);
  340. }
  341. }
  342. private void File1ButtonEdit_EditValueChanged(object sender, EventArgs e)
  343. {
  344. var arg = e as ChangingEventArgs;
  345. string fileName = arg?.NewValue?.ToString(); ;
  346. if (fileName.IsNullOrWhitespace())
  347. {
  348. vm.FileTime = DateTime.MinValue;
  349. return;
  350. }
  351. FileInfo fi = new FileInfo(fileName);
  352. if (!fi.Exists)
  353. {
  354. MsgHelper.ShowError("文件不存在!");
  355. return;
  356. }
  357. var timeStr = fi.Name.Substring(0, 14);
  358. if (DateTime.TryParseExact(timeStr, "yyyyMMddHHmmss", CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime fileTime))
  359. {
  360. vm.FileTime = fileTime;
  361. }
  362. if (vm.Fs > 1e-6)
  363. {
  364. vm.FileTimeLen = fi.Length / 4 / (vm.Fs * 1e6);
  365. }
  366. else if (vm.FileTimeLen > 1e-6)
  367. {
  368. vm.Fs = fi.Length / 4 / vm.FileTimeLen;
  369. }
  370. }
  371. private bool ValidateModelState()
  372. {
  373. dxError.ClearErrors();
  374. if (vm.File1.IsNullOrWhitespace())
  375. {
  376. dxError.SetError(File1ButtonEdit, "请选择文件1");
  377. }
  378. if (vm.File2.IsNullOrWhitespace())
  379. {
  380. dxError.SetError(File2ButtonEdit, "请选择文件2");
  381. }
  382. if (vm.Fs < 1e-6)
  383. {
  384. dxError.SetError(FsButtonEdit, "采样率不能为空!");
  385. }
  386. if (vm.DtoRange < 1e-6)
  387. {
  388. dxError.SetError(DtoRangeButtonEdit, "时差范围必须大于0");
  389. }
  390. if (vm.DfoRange < 1e-6)
  391. {
  392. dxError.SetError(DfoRangeButtonEdit, "频差范围必须大于0");
  393. }
  394. if (vm.Snr < 1e-6)
  395. {
  396. dxError.SetError(SnrButtonEdit, "信噪必须大于0");
  397. }
  398. return dxError.HasErrors;
  399. }
  400. private void gvMain_RowClick(object sender, DevExpress.XtraGrid.Views.Grid.RowClickEventArgs e)
  401. {
  402. if (e.Button == MouseButtons.Right)
  403. {
  404. popGrid.ShowPopup(e.Location);
  405. }
  406. }
  407. private async void btnMenuCg_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
  408. {
  409. var workList = gvMain.GetVisibleRows<TdmaWorkItemViewModel>();
  410. await ExecuteCsgjAsync(vm, workList);
  411. }
  412. private void btnExportSlotFile_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
  413. {
  414. var workList = gvMain.GetSelectRow<TdmaWorkItemViewModel>();
  415. if (workList.IsNullOrEmpty())
  416. {
  417. MsgHelper.ShowMsg("请选择要导出的项");
  418. return;
  419. }
  420. string outDir = ToolDialog.OpenFolder("时隙文件路径");
  421. if (outDir.IsNullOrWhitespace()) return;
  422. DirectoryUtil.CreateIfNotExists(outDir);
  423. var startTime = vm.FileTime;
  424. var endTime = vm.FileTime.AddSeconds(vm.FileTimeLen);
  425. foreach (var workItem in workList)
  426. {
  427. var slotList = workItem.SlotList.Where(m => m.SlotTime >= startTime && m.SlotTime < endTime);
  428. if (slotList.IsNullOrEmpty()) continue;
  429. var outfile = $"{vm.FileTime:yyyyMMddHHmmss}_{workItem.FreqPoint}_{workItem.Rate}_{workItem.UserId}_{workItem.MacAddr}";
  430. outfile = Path.Combine(outDir, outfile);
  431. ExportMainFile(startTime, endTime, vm.File1, outfile, slotList);
  432. }
  433. }
  434. }
  435. }