HouseDebugPageView.xaml.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  1. using ivf_tl_CustomControls;
  2. using ivf_tl_Entity.CameraEntitys;
  3. using ivf_tl_Entity.GlobalEnums;
  4. using ivf_tl_Operate.Debug;
  5. using ivf_tl_Operate.ViewModel;
  6. using ivf_tl_Operate.Windows;
  7. using Newtonsoft.Json.Linq;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Net.Sockets;
  13. using System.Runtime.ConstrainedExecution;
  14. using System.Security.Cryptography;
  15. using System.Security.Policy;
  16. using System.Text;
  17. using System.Threading.Tasks;
  18. using System.Windows;
  19. using System.Windows.Controls;
  20. using System.Windows.Data;
  21. using System.Windows.Documents;
  22. using System.Windows.Input;
  23. using System.Windows.Media;
  24. using System.Windows.Media.Imaging;
  25. using System.Windows.Media.Media3D;
  26. using System.Windows.Navigation;
  27. using System.Windows.Shapes;
  28. namespace ivf_tl_Operate.View
  29. {
  30. /// <summary>
  31. /// HouseDebugPageView.xaml 的交互逻辑
  32. /// </summary>
  33. public partial class HouseDebugPageView : UserControl
  34. {
  35. //private HouseDebugPageViewModel vm { get { return (HouseDebugPageViewModel)DataContext; } }
  36. private HouseDebugPageViewModel vm = null;
  37. /// <summary>
  38. /// 实时图像打开状态
  39. /// </summary>
  40. private bool isOpen = false;
  41. /// <summary>D2-02 第二阶段:MJPEG 预览客户端(一次性,每次开预览 new 新实例)。</summary>
  42. private MjpegStreamClient _mjpeg;
  43. private object locker = new object();
  44. //#bdbdbd #bfd87d
  45. public HouseDebugPageView(HouseDebugPageViewModel houseDebugPageViewModel)
  46. {
  47. try
  48. {
  49. InitializeComponent();
  50. vm = houseDebugPageViewModel;
  51. this.DataContext = vm;
  52. Loaded += HouseDebugPageView_Loaded;
  53. }
  54. catch (Exception ex)
  55. {
  56. ExLog(ex, "HouseDebugPageView");
  57. }
  58. }
  59. #region 通用设置
  60. private void HouseDebugPageView_Loaded(object sender, RoutedEventArgs e)
  61. {
  62. vm.MessageEvent += AddMessageInfo;
  63. vm.OpenVideoEvent += OpenVideo;
  64. vm.AddPicEvent += AddPic;
  65. foreach (var item in vm.HouseList)
  66. {
  67. switch (item.houseSn)
  68. {
  69. case 1:
  70. this._houseCCD1.Text = item.ccdId.ToString();
  71. break;
  72. case 2:
  73. this._houseCCD2.Text = item.ccdId.ToString();
  74. break;
  75. case 3:
  76. this._houseCCD3.Text = item.ccdId.ToString();
  77. break;
  78. case 4:
  79. this._houseCCD4.Text = item.ccdId.ToString();
  80. break;
  81. case 5:
  82. this._houseCCD5.Text = item.ccdId.ToString();
  83. break;
  84. case 6:
  85. this._houseCCD6.Text = item.ccdId.ToString();
  86. break;
  87. case 7:
  88. this._houseCCD7.Text = item.ccdId.ToString();
  89. break;
  90. case 8:
  91. this._houseCCD8.Text = item.ccdId.ToString();
  92. break;
  93. case 9:
  94. this._houseCCD9.Text = item.ccdId.ToString();
  95. break;
  96. case 10:
  97. this._houseCCD10.Text = item.ccdId.ToString();
  98. break;
  99. }
  100. }
  101. }
  102. private void RefshInfo()
  103. {
  104. Dispatcher.Invoke(() =>
  105. {
  106. var aa = vm.houseWellSettingList.FirstOrDefault(x => x.houseSn == vm.CurrentHouseId && x.wellSn == vm.CurrentWell);
  107. if (aa == null)
  108. {
  109. this._well_TextBlock.Text = "0";
  110. this._eepromPosition.Text = "0";
  111. }
  112. else
  113. {
  114. this._well_TextBlock.Text = aa.horizontalMotorPosition.ToString();
  115. this._eepromPosition.Text = aa.eepromClearPosition.ToString();
  116. }
  117. var bb = vm.ccdPhoto.FirstOrDefault(x => x.houseSn == vm.CurrentHouseId && x.wellSn == vm.CurrentWell);
  118. if (bb == null)
  119. {
  120. this._autoFocus.Text = "0";
  121. this._ccdOne.Text = "0";
  122. }
  123. else
  124. {
  125. this._autoFocus.Text = bb.autoFocusPosition.ToString();
  126. this._ccdOne.Text = bb.clearestPosition.ToString();
  127. }
  128. });
  129. }
  130. DateTime logTime = DateTime.Now;
  131. private void AddMessageInfo(string message)
  132. {
  133. lock (locker)
  134. {
  135. logTime = DateTime.Now;
  136. message = $"{logTime.ToString("yyyy-MM-dd HH:mm:ss")}.{logTime.Millisecond}{message}";
  137. Dispatcher.Invoke(() =>
  138. {
  139. vm.MessageInfoList.Add(message);
  140. _messageList.ScrollIntoView(message);
  141. });
  142. }
  143. }
  144. private void AddPic(string fileName, int well, int focal)
  145. {
  146. Dispatcher.Invoke(() =>
  147. {
  148. if (!File.Exists(fileName))
  149. {
  150. AddMessageInfo($"图片不存在:{fileName}");
  151. return;
  152. }
  153. string imageUrl = $"file:\\{fileName}";
  154. var imageSource = AppData.Instance.ConvertHelper.StringToBitmapImage(imageUrl);
  155. if (imageSource == null)
  156. {
  157. AddMessageInfo($"图片加载失败:{fileName}");
  158. return;
  159. }
  160. Canvas canvas = new Canvas();
  161. _warpPanelPictures.Children.Add(canvas);
  162. TextBlock text = new TextBlock();
  163. Image image = new Image();
  164. canvas.Children.Add(image);
  165. canvas.Children.Add(text);
  166. canvas.Margin = new Thickness(20, 5, 20, 0);
  167. canvas.Width = 300;
  168. canvas.Height = 330;
  169. text.Text = $"well{well} - {focal}";
  170. text.FontSize = 22;
  171. text.Foreground = new SolidColorBrush(Color.FromRgb(181, 184, 189));
  172. Canvas.SetLeft(text, 80);
  173. Canvas.SetTop(text, 302);
  174. image.Width = 300;
  175. image.Height = 300;
  176. image.Source = imageSource;
  177. image.Tag = imageUrl;
  178. //image.MouseUp += (s, arg) =>
  179. //{
  180. // text.Foreground = new SolidColorBrush(Colors.Red);
  181. // PhotoListWindow win2 = new PhotoListWindow(_warpPanelPictures.Children, image, text);
  182. // win2.ShowDialog();
  183. //};
  184. });
  185. }
  186. /// <summary>
  187. /// 打开图像
  188. /// </summary>
  189. private void OpenVideo()
  190. {
  191. try
  192. {
  193. if (isOpen) { AddMessageInfo($"图像已打开"); return; }
  194. string sessionId = vm.CurrentSessionId;
  195. if (string.IsNullOrEmpty(sessionId)) { AddMessageInfo("未借用会话,无法预览(请先初始化)"); return; }
  196. // 每次开预览 new 新实例(MjpegStreamClient 一次性,不可复用)
  197. _mjpeg = new MjpegStreamClient(ivf_tl_Operate.Helpers.ControlClient.BaseUrl);
  198. _mjpeg.FrameReceived += img => Dispatcher.Invoke(() => { _previewImage.Source = img; });
  199. _mjpeg.Stopped += reason => Dispatcher.Invoke(() =>
  200. {
  201. isOpen = false;
  202. AddMessageInfo($"⚠ {reason}"); // 明确提示操作人员手动重开(不自动重连)
  203. });
  204. _mjpeg.Start(sessionId);
  205. isOpen = true;
  206. AddMessageInfo("图像已打开(MJPEG 实时预览)");
  207. }
  208. catch (Exception ex)
  209. {
  210. ExLog(ex, "OpenVideo");
  211. AddMessageInfo($"图像打开异常:{ex.Message}");
  212. }
  213. }
  214. private void CloseVideo()
  215. {
  216. try
  217. {
  218. if (!isOpen) { AddMessageInfo($"图像未打开,无需关闭"); return; }
  219. _mjpeg?.Stop();
  220. _mjpeg = null; // 丢弃实例(一次性,下次开预览 new 新的)
  221. Dispatcher.Invoke(() => { _previewImage.Source = null; });
  222. isOpen = false;
  223. AddMessageInfo("图像已关闭");
  224. }
  225. catch (Exception ex)
  226. {
  227. ExLog(ex, "CloseVideo");
  228. AddMessageInfo($"图像关闭异常:{ex.Message}");
  229. }
  230. }
  231. private void ExLog(Exception ex, string name)
  232. {
  233. AppData.Instance.LogHelper.ExceptionLog(ex, $"HouseDebugPageView.{name}", LogEnum.RunException);
  234. }
  235. private void ShowMessageDefeat(string mess)
  236. {
  237. Dispatcher.Invoke(() =>
  238. {
  239. MessageBox.Show(mess);
  240. });
  241. //AddMessageInfo(mess);
  242. //new MessagePrompt().ShowCenterOwnerDefeat(AppData.Instance.MainWindow, mess);
  243. }
  244. private void ShowMessage(string mess)
  245. {
  246. }
  247. private void ShowMessageSuccess(string mess)
  248. {
  249. new MessagePrompt().ShowCenterOwnerSuccess(AppData.Instance.MainWindow, mess);
  250. }
  251. #endregion
  252. private void Return_Click(object sender, RoutedEventArgs e)
  253. {
  254. CloseVideo();
  255. vm.ComHouseUnit();
  256. SettingPageView settingPageView = new SettingPageView();
  257. AppData.Instance.MainWindow.LoadPage(settingPageView);
  258. }
  259. private void House_Checked(object sender, RoutedEventArgs e)
  260. {
  261. if (vm == null) return;
  262. if (!(sender is RadioButtonNoFrame radioButtonNoFrame)) return;
  263. vm.CurrentHouseId = int.Parse(radioButtonNoFrame.Tag.ToString());
  264. vm.CurrentHouse = vm.HouseList.First(x => x.houseSn == vm.CurrentHouseId);
  265. }
  266. private void CCD_Checked(object sender, RoutedEventArgs e)
  267. {
  268. if (vm == null) return;
  269. if (!(sender is RadioButtonNoFrame radioButtonNoFrame)) return;
  270. string ccdidString = radioButtonNoFrame.Tag.ToString();
  271. vm.CurrentCCDId = int.Parse(ccdidString);
  272. this._ccdId_TextBlock.Text = ccdidString;
  273. }
  274. /// <summary>
  275. /// 初始化
  276. /// </summary>
  277. /// <param name="sender"></param>
  278. /// <param name="e"></param>
  279. private async void Start_Click(object sender, RoutedEventArgs e)
  280. {
  281. try
  282. {
  283. this._house_StackPanel.IsEnabled = false;
  284. this._ccd_StackPanel.IsEnabled = false;
  285. this._startButton.IsEnabled = false;
  286. //await Task.Delay(3000 * 5);
  287. //return;
  288. await vm.ComHouseInit();
  289. RefshInfo();
  290. OpenVideo();
  291. this._button1.IsEnabled = true;
  292. this._button2.IsEnabled = true;
  293. this._button3.IsEnabled = true;
  294. this._button4.IsEnabled = true;
  295. this._button5.IsEnabled = true;
  296. this._button6.IsEnabled = true;
  297. this._button7.IsEnabled = true;
  298. this._button90.IsEnabled = true;
  299. this._button100.IsEnabled = true;
  300. this._stackPanel1.IsEnabled = true;
  301. this._stackPanel2.IsEnabled = true;
  302. this._stackPanel3.IsEnabled = true;
  303. this._stackPanel4.IsEnabled = true;
  304. }
  305. catch (Exception ex)
  306. {
  307. ExLog(ex, "Start_Click");
  308. }
  309. }
  310. /// <summary>
  311. /// 读E方
  312. /// </summary>
  313. /// <param name="sender"></param>
  314. /// <param name="e"></param>
  315. private void RedE_Click(object sender, RoutedEventArgs e)
  316. {
  317. }
  318. /// <summary>
  319. /// 读温度
  320. /// </summary>
  321. /// <param name="sender"></param>
  322. /// <param name="e"></param>
  323. private void RedTem_Click(object sender, RoutedEventArgs e)
  324. {
  325. Task.Run(() =>
  326. {
  327. vm.RedTem();
  328. });
  329. }
  330. /// <summary>
  331. /// 读压力
  332. /// </summary>
  333. /// <param name="sender"></param>
  334. /// <param name="e"></param>
  335. private void RedPre_Click(object sender, RoutedEventArgs e)
  336. {
  337. Task.Run(() =>
  338. {
  339. vm.RedPre();
  340. });
  341. }
  342. /// <summary>
  343. /// 读舱门
  344. /// </summary>
  345. /// <param name="sender"></param>
  346. /// <param name="e"></param>
  347. private void RedDoor_Click(object sender, RoutedEventArgs e)
  348. {
  349. Task.Run(() =>
  350. {
  351. vm.RedDoor();
  352. });
  353. }
  354. /// <summary>
  355. /// 开灯
  356. /// </summary>
  357. /// <param name="sender"></param>
  358. /// <param name="e"></param>
  359. private void OpenLed_Click(object sender, RoutedEventArgs e)
  360. {
  361. Task.Run(() =>
  362. {
  363. vm.OpenLed();
  364. });
  365. }
  366. /// <summary>
  367. /// 关灯
  368. /// </summary>
  369. /// <param name="sender"></param>
  370. /// <param name="e"></param>
  371. private void CloseLed_Click(object sender, RoutedEventArgs e)
  372. {
  373. Task.Run(() =>
  374. {
  375. vm.CloseLed();
  376. });
  377. }
  378. /// <summary>
  379. /// 卸载
  380. /// </summary>
  381. /// <param name="sender"></param>
  382. /// <param name="e"></param>
  383. private void End_Click(object sender, RoutedEventArgs e)
  384. {
  385. if (isOpen)
  386. {
  387. CloseVideo();
  388. }
  389. vm.IsStop = true;
  390. vm.ComHouseUnit();
  391. this._house_StackPanel.IsEnabled = true;
  392. this._ccd_StackPanel.IsEnabled = true;
  393. this._startButton.IsEnabled = true;
  394. this._button1.IsEnabled = false;
  395. this._button2.IsEnabled = false;
  396. this._button3.IsEnabled = false;
  397. this._button4.IsEnabled = false;
  398. this._button5.IsEnabled = false;
  399. this._button6.IsEnabled = false;
  400. this._button7.IsEnabled = false;
  401. this._button90.IsEnabled = false;
  402. this._button100.IsEnabled = false;
  403. this._stackPanel1.IsEnabled = false;
  404. this._stackPanel2.IsEnabled = false;
  405. this._stackPanel3.IsEnabled = false;
  406. this._stackPanel4.IsEnabled = false;
  407. }
  408. /// <summary>
  409. /// 打开进气阀
  410. /// </summary>
  411. /// <param name="sender"></param>
  412. /// <param name="e"></param>
  413. private void OpenIntake_Click(object sender, RoutedEventArgs e)
  414. {
  415. Task.Run(() =>
  416. {
  417. vm.OpenIntake();
  418. });
  419. }
  420. /// <summary>
  421. /// 关闭进气阀
  422. /// </summary>
  423. /// <param name="sender"></param>
  424. /// <param name="e"></param>
  425. private void CloseIntake_Click(object sender, RoutedEventArgs e)
  426. {
  427. Task.Run(() =>
  428. {
  429. vm.CloseIntake();
  430. });
  431. }
  432. /// <summary>
  433. /// 打开排气阀
  434. /// </summary>
  435. /// <param name="sender"></param>
  436. /// <param name="e"></param>
  437. private void OpenExhaust_Click(object sender, RoutedEventArgs e)
  438. {
  439. Task.Run(() =>
  440. {
  441. vm.OpenExhaust();
  442. });
  443. }
  444. /// <summary>
  445. /// 关闭排气阀
  446. /// </summary>
  447. /// <param name="sender"></param>
  448. /// <param name="e"></param>
  449. private void CloseExhaust_Click(object sender, RoutedEventArgs e)
  450. {
  451. Task.Run(() =>
  452. {
  453. vm.CloseExhaust();
  454. });
  455. }
  456. private void Aeration_Click(object sender, RoutedEventArgs e)
  457. {
  458. Task.Run(() =>
  459. {
  460. vm.HouseAeration();
  461. });
  462. }
  463. /// <summary>
  464. /// 写舱室进气阀时间
  465. /// </summary>
  466. /// <param name="sender"></param>
  467. /// <param name="e"></param>
  468. private void WriteOpenIntakeTime_Click(object sender, RoutedEventArgs e)
  469. {
  470. try
  471. {
  472. if (vm.CurrentHouse == null)
  473. {
  474. ShowMessageDefeat("未获取到对应的舱室信息");
  475. return;
  476. }
  477. string timeString = this._openIntakeTime_TextBox.Text.Trim();
  478. if (string.IsNullOrEmpty(timeString))
  479. {
  480. ShowMessageDefeat("请输入进气阀打开时间");
  481. return;
  482. }
  483. if (int.TryParse(timeString, out int value) && value >= 0)
  484. {
  485. Task.Run(() =>
  486. {
  487. vm.WriteOpenIntakeTime(value);
  488. if (vm.CurrentHouse != null)
  489. {
  490. vm.CurrentHouse.inletValveOpeningTime = value;
  491. vm.SetHouseInfo();
  492. }
  493. });
  494. }
  495. else
  496. {
  497. ShowMessageDefeat("进气阀打开时间只能输入大于等于0数字");
  498. return;
  499. }
  500. }
  501. catch (Exception ex)
  502. {
  503. ExLog(ex, "WriteOpenIntakeTime_Click");
  504. }
  505. }
  506. /// <summary>
  507. /// 写曝光时间
  508. /// </summary>
  509. /// <param name="sender"></param>
  510. /// <param name="e"></param>
  511. private void SetExposure_Click(object sender, RoutedEventArgs e)
  512. {
  513. try
  514. {
  515. if (vm.CurrentHouse == null)
  516. {
  517. ShowMessageDefeat("未获取到对应的舱室信息");
  518. return;
  519. }
  520. if (int.TryParse(this._exposure_TextBox.Text.Trim(), out int newExposure) && newExposure >= 0)
  521. {
  522. vm.SetExposure(newExposure);
  523. if (vm.CurrentHouse != null)
  524. {
  525. vm.CurrentHouse.ccdExposure = newExposure;
  526. vm.SetHouseInfo();
  527. }
  528. return;
  529. }
  530. ShowMessageDefeat("曝光值只能输入大于等于0数字");
  531. return;
  532. }
  533. catch (Exception ex)
  534. {
  535. ExLog(ex, "SetExposure_Click");
  536. }
  537. }
  538. /// <summary>
  539. /// 水平电机复位
  540. /// </summary>
  541. /// <param name="sender"></param>
  542. /// <param name="e"></param>
  543. private void HorizontalMotorReset_Click(object sender, RoutedEventArgs e)
  544. {
  545. Task.Run(() =>
  546. {
  547. vm.HorizontalMotorReset();
  548. RefshInfo();
  549. });
  550. }
  551. /// <summary>
  552. /// 保存当前well水平电机位置
  553. /// </summary>
  554. /// <param name="sender"></param>
  555. /// <param name="e"></param>
  556. private void SaveWellHorizontalMotor_Click(object sender, RoutedEventArgs e)
  557. {
  558. if (vm.CurrentHouse == null)
  559. {
  560. ShowMessageDefeat("未获取到对应的舱室信息");
  561. return;
  562. }
  563. Task.Run(() =>
  564. {
  565. try
  566. {
  567. vm.SaveWellHor();
  568. if (!vm.SetWellMotorPosition())
  569. {
  570. ShowMessageDefeat("数据库保存失败");
  571. return;
  572. }
  573. var aa = vm.houseWellSettingList.FirstOrDefault(x => x.houseSn == vm.CurrentHouseId && x.wellSn == vm.CurrentWell);
  574. if (aa != null)
  575. {
  576. aa.horizontalMotorPosition = vm.CurrentHor;
  577. Dispatcher.Invoke(() =>
  578. {
  579. this._well_TextBlock.Text = aa.horizontalMotorPosition.ToString();
  580. });
  581. }
  582. else
  583. {
  584. ShowMessageDefeat("未获取到well位置");
  585. return;
  586. }
  587. }
  588. catch (Exception ex)
  589. {
  590. ExLog(ex, "SaveWellHorizontalMotor_Click");
  591. }
  592. });
  593. }
  594. /// <summary>
  595. /// 水平电机正向移动
  596. /// </summary>
  597. /// <param name="sender"></param>
  598. /// <param name="e"></param>
  599. private void HorizontalMotorForward_Click(object sender, RoutedEventArgs e)
  600. {
  601. string forwardString = this._horizontalMotorForward_TextBox.Text.Trim();
  602. if (string.IsNullOrEmpty(forwardString))
  603. {
  604. MessageBox.Show("请输入正向移动脉冲");
  605. return;
  606. }
  607. if (int.TryParse(forwardString, out int value))
  608. {
  609. Task.Run(() =>
  610. {
  611. vm.HorizontalMotorForward(value);
  612. });
  613. }
  614. else
  615. {
  616. MessageBox.Show("正向移动脉冲只能输入数字");
  617. return;
  618. }
  619. }
  620. /// <summary>
  621. /// 水平电机反向运动
  622. /// </summary>
  623. /// <param name="sender"></param>
  624. /// <param name="e"></param>
  625. private void HorizontalMotorBackward_Click(object sender, RoutedEventArgs e)
  626. {
  627. string backwardString = this._horizontalMotorBackward_TextBox.Text.Trim();
  628. if (string.IsNullOrEmpty(backwardString))
  629. {
  630. MessageBox.Show("请输入反向移动脉冲");
  631. return;
  632. }
  633. if (int.TryParse(backwardString, out int value))
  634. {
  635. Task.Run(() =>
  636. {
  637. vm.HorizontalMotorBackward(value);
  638. });
  639. }
  640. else
  641. {
  642. MessageBox.Show("反向移动脉冲只能输入数字");
  643. return;
  644. }
  645. }
  646. /// <summary>
  647. /// 水平电机移动到指定Well
  648. /// </summary>
  649. /// <param name="sender"></param>
  650. /// <param name="e"></param>
  651. private void HorizontalMotorToWell_Click(object sender, RoutedEventArgs e)
  652. {
  653. string wellString = this._horizontalMotorToWell_TextBox.Text.Trim();
  654. if (string.IsNullOrEmpty(wellString))
  655. {
  656. ShowMessageDefeat("请输入目标well");
  657. return;
  658. }
  659. if (int.TryParse(wellString, out int value) && value >= 1 && value <= 16)
  660. {
  661. Task.Run(() =>
  662. {
  663. vm.HorizontalMotorToWell(value);
  664. RefshInfo();
  665. });
  666. }
  667. else
  668. {
  669. ShowMessageDefeat("目标well只能输入1-16的数字");
  670. return;
  671. }
  672. }
  673. /// <summary>
  674. /// 下一well
  675. /// </summary>
  676. /// <param name="sender"></param>
  677. /// <param name="e"></param>
  678. private void HorizontalMotorNextWell_Click(object sender, RoutedEventArgs e)
  679. {
  680. Task.Run(() =>
  681. {
  682. vm.HorizontalMotorToWell(vm.CurrentWell + 1);
  683. RefshInfo();
  684. });
  685. }
  686. /// <summary>
  687. /// 垂直电机复位
  688. /// </summary>
  689. /// <param name="sender"></param>
  690. /// <param name="e"></param>
  691. private void VerticalMotorResetWait_Click(object sender, RoutedEventArgs e)
  692. {
  693. Task.Run(() =>
  694. {
  695. vm.VerticalMotorReset();
  696. vm.CurrentFocal = 0;
  697. });
  698. }
  699. /// <summary>
  700. /// 垂直电机正向移动
  701. /// </summary>
  702. /// <param name="sender"></param>
  703. /// <param name="e"></param>
  704. private void VerticalMotorForward_Click(object sender, RoutedEventArgs e)
  705. {
  706. string forwardString = this._verticalMotorForward_TextBox.Text.Trim();
  707. if (string.IsNullOrEmpty(forwardString))
  708. {
  709. MessageBox.Show("请输入正向移动脉冲");
  710. return;
  711. }
  712. if (int.TryParse(forwardString, out int value))
  713. {
  714. Task.Run(() =>
  715. {
  716. vm.VerticalMotorForward(value);
  717. });
  718. }
  719. else
  720. {
  721. MessageBox.Show("正向移动脉冲只能输入数字");
  722. return;
  723. }
  724. }
  725. /// <summary>
  726. /// 垂直电机反向运动
  727. /// </summary>
  728. /// <param name="sender"></param>
  729. /// <param name="e"></param>
  730. private void VerticalMotorBackward_Click(object sender, RoutedEventArgs e)
  731. {
  732. string backwardString = this._verticalMotorBackward_TextBox.Text.Trim();
  733. if (string.IsNullOrEmpty(backwardString))
  734. {
  735. MessageBox.Show("请输入反向移动脉冲");
  736. return;
  737. }
  738. if (int.TryParse(backwardString, out int value))
  739. {
  740. Task.Run(() =>
  741. {
  742. vm.VerticalMotorBackward(value);
  743. });
  744. }
  745. else
  746. {
  747. MessageBox.Show("反向移动脉冲只能输入数字");
  748. return;
  749. }
  750. }
  751. /// <summary>
  752. /// 垂直电机绝对运动
  753. /// </summary>
  754. /// <param name="sender"></param>
  755. /// <param name="e"></param>
  756. private void VerticalMotorAbsolute_Click(object sender, RoutedEventArgs e)
  757. {
  758. string absoluteString = this._verticalMotorAbsolute_TextBox.Text.Trim();
  759. if (string.IsNullOrEmpty(absoluteString))
  760. {
  761. MessageBox.Show("请输入目标脉冲");
  762. return;
  763. }
  764. if (int.TryParse(absoluteString, out int value) && value >= 0 && value <= vm.tLSetting.verticalMotorPulseMax)
  765. {
  766. Task.Run(() =>
  767. {
  768. vm.VerticalMotorAbsolute(value);
  769. });
  770. }
  771. else
  772. {
  773. MessageBox.Show($"目标脉冲只能输入0-{vm.tLSetting.verticalMotorPulseMax}的数字");
  774. return;
  775. }
  776. }
  777. /// <summary>
  778. /// 保存垂直电机间隔脉冲
  779. /// </summary>
  780. /// <param name="sender"></param>
  781. /// <param name="e"></param>
  782. private void SaveVerSpacePulse_Click(object sender, RoutedEventArgs e)
  783. {
  784. try
  785. {
  786. if (vm.CurrentHouse == null)
  787. {
  788. ShowMessageDefeat("未获取到对应的舱室信息");
  789. return;
  790. }
  791. if (int.TryParse(this._verticalMotorForward_TextBox.Text.Trim(), out int newValue) && newValue > 0 && newValue <= vm.tLSetting.verticalMotorPulseMax)
  792. {
  793. Task.Run(() =>
  794. {
  795. vm.WriteOVerSpace(newValue);
  796. vm.CurrentHouse.verticalMotorSpacePulse = newValue;
  797. vm.SetHouseInfo();
  798. });
  799. }
  800. else
  801. {
  802. AddMessageInfo($"垂直电机间隔脉冲只能输入0-{vm.tLSetting.verticalMotorPulseMax}的数字");
  803. }
  804. }
  805. catch (Exception ex)
  806. {
  807. AddMessageInfo($"保存垂直电机间隔脉冲异常:{ex.Message}");
  808. ExLog(ex, "SaveVerSpacePulse_Click");
  809. }
  810. }
  811. /// <summary>
  812. /// 清空
  813. /// </summary>
  814. /// <param name="sender"></param>
  815. /// <param name="e"></param>
  816. private void Clear_Click(object sender, RoutedEventArgs e)
  817. {
  818. vm.MessageInfoList.Clear();
  819. this._warpPanelPictures.Children.Clear();
  820. }
  821. /// <summary>
  822. /// 一键电机准备
  823. /// </summary>
  824. /// <param name="sender"></param>
  825. /// <param name="e"></param>
  826. private void Motor_Click(object sender, RoutedEventArgs e)
  827. {
  828. Task.Run(() =>
  829. {
  830. vm.MototReady();
  831. });
  832. }
  833. /// <summary>
  834. /// 单张抓拍
  835. /// </summary>
  836. /// <param name="sender"></param>
  837. /// <param name="e"></param>
  838. private void GetPic_Click(object sender, RoutedEventArgs e)
  839. {
  840. try
  841. {
  842. if (!isOpen)
  843. {
  844. AddMessageInfo("开启实时图像以后才可以拍照");
  845. return;
  846. }
  847. if (vm.CurrentHouse == null)
  848. {
  849. AddMessageInfo("获取舱室信息失败");
  850. return;
  851. }
  852. string path = AppData.Instance.LogHelper.GetDeBugDanZhangDirectory(vm.CurrentHouse.houseSn, vm.CurrentWell);
  853. if (!Directory.Exists(path))
  854. {
  855. Directory.CreateDirectory(path);
  856. }
  857. string fullName = $"{path}house{vm.CurrentHouse.houseSn}_{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fff")}_{vm.CurrentHor}-{vm.CurrentVer}.jpg";
  858. if (!vm.SavePic(fullName)) return;
  859. AddPic(fullName, vm.CurrentWell, vm.CurrentFocal);
  860. }
  861. catch (Exception ex)
  862. {
  863. ExLog(ex, "GetPic_Click");
  864. AddMessageInfo($"单张抓拍异常:{ex.Message}");
  865. }
  866. }
  867. /// <summary>
  868. /// 水平抓拍
  869. /// </summary>
  870. /// <param name="sender"></param>
  871. /// <param name="e"></param>
  872. private void ShuiPingPic_Click(object sender, RoutedEventArgs e)
  873. {
  874. if (vm.CurrentHouse == null)
  875. {
  876. AddMessageInfo("获取舱室信息失败");
  877. return;
  878. }
  879. if (!isOpen)
  880. {
  881. AddMessageInfo("开启实时图像以后才可以拍照");
  882. return;
  883. }
  884. Task.Run(() =>
  885. {
  886. vm.ShuiPingZhuaPai();
  887. });
  888. }
  889. /// <summary>
  890. /// 结束抓图
  891. /// </summary>
  892. /// <param name="sender"></param>
  893. /// <param name="e"></param>
  894. private void EndPic_Click(object sender, RoutedEventArgs e)
  895. {
  896. vm.IsStop = true;
  897. }
  898. /// <summary>
  899. /// 清晰图层抓图
  900. /// </summary>
  901. /// <param name="sender"></param>
  902. /// <param name="e"></param>
  903. private async void AutoFocus_Click(object sender, RoutedEventArgs e)
  904. {
  905. try
  906. {
  907. if (vm.CurrentHouse == null)
  908. {
  909. ShowMessageDefeat("获取舱室信息失败");
  910. return;
  911. }
  912. if (int.TryParse(this._autoFocusNum_TextBox.Text.Trim(), out int autoFocusNum) && autoFocusNum > 0 && int.TryParse(this._autoFocus_TextBox.Text.Trim(), out int xun) && xun > 0)
  913. {
  914. this._auto_Button.IsEnabled = false;
  915. await vm.AutoFocusPic(autoFocusNum, xun);
  916. this._auto_Button.IsEnabled = true;
  917. }
  918. else
  919. {
  920. ShowMessageDefeat($"请输入正确的拍摄次数以及循环次数");
  921. }
  922. }
  923. catch (Exception ex)
  924. {
  925. ExLog(ex, "AutoFocus_Click");
  926. AddMessageInfo($"清晰图层抓图异常:{ex.Message}");
  927. }
  928. }
  929. private void CloseVideo_Click(object sender, RoutedEventArgs e)
  930. {
  931. try
  932. {
  933. CloseVideo();
  934. }
  935. catch (Exception ex)
  936. {
  937. ExLog(ex, "CloseVideo_Click");
  938. AddMessageInfo($"图像关闭异常:{ex.Message}");
  939. }
  940. }
  941. /// <summary>
  942. /// M2-05 场景A 一键全自动标定(沙盒)。对选中 well(默认 16 well)逐个跑四步标定,
  943. /// 合格绿/伪峰红实时显示,结果作出厂基准 scene=0 存档 + 写 calibration.json。
  944. /// 硬件复用调试页已借用并打开的 comBin/camera(经适配器暴露为 HAL 接口),不二次 Open/Init。
  945. /// </summary>
  946. private async void OneClickCalibrate_Click(object sender, RoutedEventArgs e)
  947. {
  948. try
  949. {
  950. if (vm.CurrentHouse == null)
  951. {
  952. ShowMessageDefeat("获取舱室信息失败,请先初始化舱室");
  953. return;
  954. }
  955. if (vm.IsCalibrating)
  956. {
  957. AddMessageInfo("[一键标定]已在标定中");
  958. return;
  959. }
  960. this._oneClickCalib_Button.IsEnabled = false;
  961. try
  962. {
  963. // 沙盒默认全 16 well 逐个跑(如需勾选子集,传入选中 well 列表即可)。
  964. await vm.OneClickCalibrate(null);
  965. }
  966. finally
  967. {
  968. this._oneClickCalib_Button.IsEnabled = true;
  969. }
  970. }
  971. catch (Exception ex)
  972. {
  973. ExLog(ex, "OneClickCalibrate_Click");
  974. AddMessageInfo($"一键标定异常:{ex.Message}");
  975. }
  976. }
  977. /// <summary>M2-05 中止一键标定(当前 well 结束后停止,已完成结果保留)。</summary>
  978. private void StopCalibrate_Click(object sender, RoutedEventArgs e)
  979. {
  980. try
  981. {
  982. vm.StopCalibrate();
  983. }
  984. catch (Exception ex)
  985. {
  986. ExLog(ex, "StopCalibrate_Click");
  987. }
  988. }
  989. /// <summary>
  990. /// M2-07 载入选定 well 当前生效的拍摄层配置(well 级覆盖优先,空则显示继承的设备级值占位),
  991. /// 回填三个手调框并触发一次预览。
  992. /// </summary>
  993. private void LoadManualTune_Click(object sender, RoutedEventArgs e)
  994. {
  995. try
  996. {
  997. if (vm.CurrentHouse == null)
  998. {
  999. ShowMessageDefeat("获取舱室信息失败,请先初始化舱室");
  1000. return;
  1001. }
  1002. if (vm.ManualTuneWell < 1 || vm.ManualTuneWell > 16)
  1003. {
  1004. ShowMessageDefeat("well 只能为 1-16");
  1005. return;
  1006. }
  1007. vm.LoadManualLayerSetting(vm.ManualTuneWell);
  1008. }
  1009. catch (Exception ex)
  1010. {
  1011. ExLog(ex, "LoadManualTune_Click");
  1012. }
  1013. }
  1014. /// <summary>
  1015. /// M2-07 实时预览:用该 well 标定 FocusZ + 当前手调值调 M2-02 ComputeLayerPositions 算各层 Z(关联 V-045)。
  1016. /// </summary>
  1017. private void PreviewManualTune_Click(object sender, RoutedEventArgs e)
  1018. {
  1019. try
  1020. {
  1021. if (vm.CurrentHouse == null)
  1022. {
  1023. ShowMessageDefeat("获取舱室信息失败,请先初始化舱室");
  1024. return;
  1025. }
  1026. vm.PreviewManualLayers();
  1027. }
  1028. catch (Exception ex)
  1029. {
  1030. ExLog(ex, "PreviewManualTune_Click");
  1031. }
  1032. }
  1033. /// <summary>
  1034. /// M2-07 存为该 well 默认:校验通过后写 house_well_setting well 级覆盖
  1035. /// (focus_layer_spacing_pulse/focus_layer_count + 复用 move_down_layer),留空继承设备级。
  1036. /// </summary>
  1037. private void SaveManualTune_Click(object sender, RoutedEventArgs e)
  1038. {
  1039. try
  1040. {
  1041. if (vm.CurrentHouse == null)
  1042. {
  1043. ShowMessageDefeat("获取舱室信息失败,请先初始化舱室");
  1044. return;
  1045. }
  1046. if (vm.SaveManualLayerTune())
  1047. {
  1048. ShowMessageSuccess("手调拍摄层已存为该 well 默认");
  1049. }
  1050. else
  1051. {
  1052. ShowMessageDefeat("手调拍摄层保存失败(见日志,可能为非法值或接口失败)");
  1053. }
  1054. }
  1055. catch (Exception ex)
  1056. {
  1057. ExLog(ex, "SaveManualTune_Click");
  1058. }
  1059. }
  1060. private void OpenVideo_Click(object sender, RoutedEventArgs e)
  1061. {
  1062. try
  1063. {
  1064. OpenVideo();
  1065. }
  1066. catch (Exception ex)
  1067. {
  1068. ExLog(ex, "OpenVideo_Click");
  1069. AddMessageInfo($"图像打开异常:{ex.Message}");
  1070. }
  1071. }
  1072. /// <summary>
  1073. /// 保存自动对焦起点
  1074. /// </summary>
  1075. /// <param name="sender"></param>
  1076. /// <param name="e"></param>
  1077. private void SaveAutoFocus_Click(object sender, RoutedEventArgs e)
  1078. {
  1079. try
  1080. {
  1081. if (vm.SetWellAutoFocus())
  1082. {
  1083. var bb = vm.ccdPhoto.FirstOrDefault(x => x.houseSn == vm.CurrentHouseId && x.wellSn == vm.CurrentWell);
  1084. if (bb != null) bb.autoFocusPosition = vm.CurrentVer;
  1085. this._autoFocus.Text = vm.CurrentVer.ToString();
  1086. AddMessageInfo($"自动对焦起点保存成功");
  1087. }
  1088. else
  1089. {
  1090. AddMessageInfo($"自动对焦起点保存失败");
  1091. }
  1092. }
  1093. catch (Exception ex)
  1094. {
  1095. ExLog(ex, "SaveAutoFocus_Click");
  1096. AddMessageInfo($"保存自动对焦起点异常:{ex.Message}");
  1097. }
  1098. }
  1099. private void _autoFocusNum_TextBox_TextChanged(object sender, TextChangedEventArgs e)
  1100. {
  1101. TextBox passwordBox = sender as TextBox;
  1102. if (passwordBox == null) return;
  1103. string ss = passwordBox.Text.Trim();
  1104. if (string.IsNullOrEmpty(ss))
  1105. {
  1106. passwordBox.Background = (VisualBrush)this.FindResource("HelpBrush2");
  1107. }
  1108. else
  1109. {
  1110. passwordBox.Background = new SolidColorBrush(Colors.White);
  1111. }
  1112. }
  1113. private void _autoFocus_TextBox_TextChanged(object sender, TextChangedEventArgs e)
  1114. {
  1115. TextBox passwordBox = sender as TextBox;
  1116. if (passwordBox == null) return;
  1117. string ss = passwordBox.Text.Trim();
  1118. if (string.IsNullOrEmpty(ss))
  1119. {
  1120. passwordBox.Background = (VisualBrush)this.FindResource("HelpBrush3");
  1121. }
  1122. else
  1123. {
  1124. passwordBox.Background = new SolidColorBrush(Colors.White);
  1125. }
  1126. }
  1127. private void Paiqi_Click(object sender, RoutedEventArgs e)
  1128. {
  1129. Task.Run(() =>
  1130. {
  1131. vm.HouseVent();
  1132. });
  1133. }
  1134. private void WriteOpenVentTime_Click(object sender, RoutedEventArgs e)
  1135. {
  1136. try
  1137. {
  1138. if (vm.CurrentHouse == null)
  1139. {
  1140. ShowMessageDefeat("未获取到对应的舱室信息");
  1141. return;
  1142. }
  1143. string timeString = this._openVentTime_TextBox.Text.Trim();
  1144. if (string.IsNullOrEmpty(timeString))
  1145. {
  1146. ShowMessageDefeat("请输入排气阀打开时间");
  1147. return;
  1148. }
  1149. if (int.TryParse(timeString, out int value) && value >= 0)
  1150. {
  1151. Task.Run(() =>
  1152. {
  1153. vm.WriteOpenVentTime(value);
  1154. //if (vm.CurrentHouse != null)
  1155. //{
  1156. // vm.CurrentHouse.inletValveOpeningTime = value;
  1157. // vm.SetHouseInfo();
  1158. //}
  1159. });
  1160. }
  1161. else
  1162. {
  1163. ShowMessageDefeat("排气阀打开时间只能输入大于等于0数字");
  1164. return;
  1165. }
  1166. }
  1167. catch (Exception ex)
  1168. {
  1169. ExLog(ex, "WriteOpenVentTime_Click");
  1170. }
  1171. }
  1172. private void ReadOpenVentTime_Click(object sender, RoutedEventArgs e)
  1173. {
  1174. Task.Run(() =>
  1175. {
  1176. vm.RedVentTime();
  1177. });
  1178. }
  1179. }
  1180. }