版博士V2.0程序
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 

2209 rader
104 KiB

  1. using Advantech.Motion;
  2. using AssistClient.Device;
  3. using AssistClient.Utils;
  4. using Models;
  5. using Newtonsoft.Json;
  6. using Newtonsoft.Json.Linq;
  7. using OpenCvSharp;
  8. using SqlSugar;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.ComponentModel;
  12. using System.Data;
  13. using System.Drawing;
  14. using System.Drawing.Imaging;
  15. using System.Dynamic;
  16. using System.IO;
  17. using System.Linq;
  18. using System.Text;
  19. using System.Threading;
  20. using System.Threading.Tasks;
  21. using System.Windows.Forms;
  22. using Yolo5;
  23. using static AssistClient.Device.SizeLib;
  24. using Point = System.Drawing.Point;
  25. using Size = System.Drawing.Size;
  26. namespace AssistClient
  27. {
  28. public partial class FrmMain : Form
  29. {
  30. #region pic缩放变量
  31. private double ratio = 1; // 图片的起始显示比例
  32. private double ratioStep = 0.1;
  33. private Size pic_size;
  34. private int xPos;
  35. private int yPos;
  36. #endregion
  37. private bool bExitApp = false;
  38. private Service.ProductService svcProduct = new Service.ProductService();
  39. private Service.OrderService svcOrder = new Service.OrderService();
  40. private DevContainer devContainer = new DevContainer();
  41. private Queue<scannerCBmpLoc> scannerCBmpQueue = new Queue<scannerCBmpLoc>();
  42. private int sizeBmpNum = 0, sizeBmpNumResult = 0;
  43. private string SN = "";
  44. private int OrderId = 0;
  45. private JArray currProductMarkList = null;
  46. private int currDefectIndex = 0;
  47. private List<DefectStruct> defectList = new List<DefectStruct>();
  48. private Dictionary<string, Bitmap> defectBmpsDir = new Dictionary<string, Bitmap>();
  49. private Dictionary<string, List<List<string>>> defectInfoDir = new Dictionary<string, List<List<string>>>();
  50. private object myLock = new object();
  51. private WarningEnum warningLevel;//警告等级
  52. private CurrentPTEnum currentPT;//当前点位
  53. private CurrentStateEnum currentState;//当前状态
  54. /// <summary>
  55. /// 当前流程ID,暂停/继续时使用
  56. /// </summary>
  57. private int currProcessIndex = -1;
  58. private Models.Product currProductModel = null;//当前产品
  59. private System.Timers.Timer timer = new System.Timers.Timer();
  60. Yolo_Class yolo = new Yolo_Class();
  61. private class scannerCBmpLoc
  62. {
  63. public scannerCBmpLoc(string path, double posX, double posY)
  64. {
  65. Path = path;
  66. PosX = posX;
  67. PosY = posY;
  68. }
  69. public scannerCBmpLoc(Bitmap bmp, double posX, double posY)
  70. {
  71. BMP = bmp;
  72. PosX = posX;
  73. PosY = posY;
  74. }
  75. public Bitmap BMP { get; private set; }
  76. public string Path { get; private set; }
  77. public double PosX { get; private set; }
  78. public double PosY { get; private set; }
  79. }
  80. public FrmMain()
  81. {
  82. InitializeComponent();
  83. this.tsbtnCloseDev.Visible = false;
  84. this.dgvProcess.AutoGenerateColumns = false;
  85. //显示行号与列宽度自动调整
  86. dgvProcess.RowHeadersVisible = true;
  87. dgvProcess.RowHeadersWidth = 30;
  88. dgvProcess.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
  89. //dgvProcess.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;//数据量过百绑定太变
  90. dgvProcess.RowPostPaint += (sender, e) =>//序号列头
  91. {
  92. Utils.Util.showRowNum_onDataGrid_RowPostPaint(this.dgvProcess, sender, e);
  93. };
  94. for (int i = 0; i < dgvProcess.Columns.Count; i++)//禁止点击列头排序
  95. dgvProcess.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
  96. //模糊查询,Append自动填充
  97. this.cbxSN.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
  98. this.cbxSN.AutoCompleteSource = AutoCompleteSource.ListItems;
  99. }
  100. private void FrmMain_Load(object sender, EventArgs e)
  101. {
  102. this.tsbtnPause.Left = this.tsbtnGoDownPT.Left = this.gpbZAxis.Right + 10;
  103. }
  104. private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
  105. {
  106. if (devContainer.state)
  107. {
  108. MessageBox.Show("请先停止设备后才能关闭程序!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  109. e.Cancel = true;
  110. return;
  111. }
  112. if (!bExitApp && MessageBox.Show($"确认退出?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
  113. {
  114. e.Cancel = true;
  115. return;
  116. }
  117. }
  118. private void FrmMain_FormClosed(object sender, FormClosedEventArgs e)
  119. {
  120. Application.Exit();
  121. System.GC.Collect();
  122. System.Environment.Exit(0);
  123. }
  124. #region 菜单
  125. private void 设备调试ToolStripMenuItem_Click(object sender, EventArgs e)
  126. {
  127. if (devContainer.state)
  128. {
  129. MessageBox.Show("请先停止设备,再进行设备调试!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  130. return;
  131. }
  132. FrmDebug3 frm = new FrmDebug3();
  133. frm.ShowDialog();
  134. }
  135. private void tsMenuPTSetting_Click(object sender, EventArgs e)
  136. {
  137. if (devContainer.state)
  138. {
  139. MessageBox.Show("请先停止设备,再进行设置!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  140. return;
  141. }
  142. FrmPTSetting from = new FrmPTSetting();
  143. from.ShowDialog();
  144. }
  145. private void tsMenuCmdSetting_Click(object sender, EventArgs e)
  146. {
  147. if (devContainer.state)
  148. {
  149. MessageBox.Show("请先停止设备,再进行设置!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  150. return;
  151. }
  152. FrmCMDProcess from = new FrmCMDProcess();
  153. from.ShowDialog();
  154. }
  155. private void tsMenuSysSetting_Click(object sender, EventArgs e)
  156. {
  157. FrmSysSetting frmSetting = new FrmSysSetting();
  158. frmSetting.ShowDialog();
  159. }
  160. #endregion
  161. #region 图片缩放控制
  162. private void reloadPic(Bitmap bmp, List<List<string>> defectInfor2RepairTable, DefectStruct defectInfo)
  163. {
  164. //绘框
  165. if (defectInfor2RepairTable != null && defectInfo != null)
  166. {
  167. AddTextEvent("更新图片", $"打标:MainX={defectInfo.MainX},MainY={defectInfo.MainY},CurrIndex={defectInfo.CurrIndex},RepairTable={JsonConvert.SerializeObject(defectInfor2RepairTable)}", warningLevel);
  168. Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
  169. mat = yolo.RepairTableDrawRec(defectInfor2RepairTable, defectInfo.MainX, defectInfo.MainY, defectInfo.CurrIndex, mat);
  170. bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  171. }
  172. else
  173. AddTextEvent("更新图片", "无需打标!", warningLevel);
  174. var newSize = Util.getNewSize(splitContainer2.Panel1.ClientSize, new Size(bmp.Size.Width*100, bmp.Size.Height*100));
  175. this.pnlPic.Size = newSize;
  176. if (this.pnlPic.Width < splitContainer2.Panel1.ClientSize.Width)
  177. this.pnlPic.Left = (splitContainer2.Panel1.ClientSize.Width - this.pnlPic.Width) / 2;
  178. if (this.pnlPic.Height < splitContainer2.Panel1.ClientSize.Height)
  179. this.pnlPic.Top = (splitContainer2.Panel1.ClientSize.Height - this.pnlPic.Height) / 2;
  180. ratio = 1.0;// 图片的起始显示比例
  181. Size size = bmp.Size;
  182. //this.pnlPic.ClientSize = new Size(this.pnlPic.ClientSize.Width,
  183. // (int)(this.pnlPic.ClientSize.Width * (size.Height * 1.0f / size.Width)));
  184. this.pictureBox1.Size = this.pnlPic.ClientSize;
  185. this.pictureBox1.Location = new Point(0, 0);
  186. this.pictureBox1.Image = bmp;//del
  187. pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
  188. pictureBox1.MouseWheel += new MouseEventHandler(pictureBox1_MouseWheel);
  189. pictureBox1.MouseMove += pictureBox1_MouseMove;
  190. pictureBox1.MouseDown += pictureBox1_MouseDown;
  191. this.ActiveControl = this.pictureBox1; // 设置焦点
  192. pic_size = this.pnlPic.ClientSize;
  193. }
  194. private void pictureBox1_MouseWheel(object sender, MouseEventArgs e)
  195. {
  196. Point pictureBoxPoint = this.PointToClient(Cursor.Position);
  197. //this.Text = $"{e.X}:{e.Y}; {pictureBoxPoint.X}:{pictureBoxPoint.Y}; {pictureBox1.Left}:{pictureBox1.Top}; " +
  198. // $"{this.pictureBox1.Width}:{this.pictureBox1.Height}; {this.Width}:{this.Height}; " +
  199. // $"Cursor:{Cursor.Position.X}:{Cursor.Position.Y}";
  200. if (e.Delta > 0)
  201. {
  202. ratio += ratioStep;
  203. if (ratio > 100) // 放大上限
  204. ratio = 100;
  205. else
  206. {
  207. int x = (int)(pictureBox1.Left - e.X * (e.X * 1.0d / pictureBox1.Width * ratioStep) + 0.5);
  208. int y = (int)(pictureBox1.Top - e.Y * (e.Y * 1.0d / pictureBox1.Height * ratioStep) + 0.5);
  209. //this.Text = $"{pictureBox1.Width}-{pic_size.Width};{ratio},{pictureBox1.Left}-{e.X}* 比例:{e.X*1.0d/pictureBox1.Width}={e.X}/{pictureBox1.Width} * {(ratioStep)}={x} | " +
  210. // $"{pictureBox1.Top}-{e.Y}* {e.Y * 1.0f / pictureBox1.Height * (ratio - 1.0d)}={y}";
  211. this.changePictureBoxSize(new Point(x, y), ratio);
  212. }
  213. }
  214. else if (ratio - ratioStep >= 1)
  215. {
  216. ratio -= ratioStep;
  217. //if (ratio < 0.1) // 放大下限
  218. // ratio = 0.1;
  219. //else
  220. int x = (int)(pictureBox1.Left + e.X * (e.X * 1.0d / pictureBox1.Width * ratioStep) + 0.5);
  221. int y = (int)(pictureBox1.Top + e.Y * (e.Y * 1.0d / pictureBox1.Height * ratioStep) + 0.5);
  222. this.changePictureBoxSize(new Point(x, y), ratio);
  223. }
  224. }
  225. private void changePictureBoxSize(Point location, double ratio)
  226. {
  227. var picSize = pictureBox1.Size;
  228. picSize.Width = Convert.ToInt32(pic_size.Width * ratio);
  229. picSize.Height = Convert.ToInt32(pic_size.Height * ratio);
  230. pictureBox1.Size = picSize;
  231. if (location.X > 0) location.X = 0;
  232. if (location.Y > 0) location.Y = 0;
  233. if (picSize.Width + location.X < this.pnlPic.ClientSize.Width) location.X = -(picSize.Width - this.pnlPic.ClientSize.Width);
  234. if (picSize.Height + location.Y < this.pnlPic.ClientSize.Height) location.Y = -(picSize.Height - this.pnlPic.ClientSize.Height);
  235. //Point location = new Point();
  236. //location.X = (this.ClientSize.Width - this.pictureBox1.Width) / 2;
  237. //location.Y = (this.ClientSize.Height - this.pictureBox1.Height) / 2;
  238. this.pictureBox1.Location = location;
  239. }
  240. private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
  241. {
  242. try
  243. {
  244. // 鼠标按下拖拽图片
  245. if (e.Button == MouseButtons.Left)
  246. {
  247. this.Text = $"{e.X}:{e.Y};{xPos}:{yPos}";
  248. // 限制拖拽出框
  249. if (pictureBox1.Width > this.pnlPic.ClientSize.Width
  250. || pictureBox1.Height > this.pnlPic.ClientSize.Height)
  251. {
  252. int moveX = e.X - xPos;
  253. int moveY = e.Y - yPos;
  254. if ((pictureBox1.Left + moveX) <= 0
  255. && (pictureBox1.Top + moveY) <= 0
  256. && (pictureBox1.Right + moveX) >= this.pnlPic.ClientSize.Width
  257. && (pictureBox1.Bottom + moveY) >= this.pnlPic.ClientSize.Height)
  258. {
  259. pictureBox1.Left += moveX;//设置x坐标.
  260. pictureBox1.Top += moveY;//设置y坐标.
  261. }
  262. }
  263. }
  264. }
  265. catch (Exception dd)
  266. {
  267. MessageBox.Show(dd.Message);
  268. }
  269. }
  270. private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
  271. {
  272. xPos = e.X;//当前x坐标.
  273. yPos = e.Y;//当前y坐标.
  274. }
  275. #endregion
  276. #region 中断命令Fun
  277. private Thread threadProcess;
  278. /// <summary>
  279. /// 启动
  280. /// </summary>
  281. private void startCommand()
  282. {
  283. if (!devContainer.state || warningLevel != WarningEnum.Normal || currentState != CurrentStateEnum.等待启动)
  284. return;
  285. if (currentPT == CurrentPTEnum.MakeTag)
  286. {
  287. AddTextEvent("启动", "打标未结束,非可启动状态!", warningLevel);
  288. return;
  289. }
  290. if (!devContainer.devAxis.isReady())
  291. {
  292. AddTextEvent("启动", "轴状态异常,不可启动!", warningLevel);
  293. return;
  294. }
  295. if (!devContainer.devAxis.IsReset)
  296. {
  297. AddTextEvent("启动", "轴需先进行复位操作!", WarningEnum.High);
  298. return;
  299. }
  300. devContainer.io_output(CMDName.启动按钮);
  301. //devContainer.io_output(CMDName.绿灯输出);
  302. //devContainer.io_output(CMDName.暂停按钮, false, true, 0);
  303. //devContainer.io_output(CMDName.红灯输出, false, true, 0);
  304. //devContainer.io_output(CMDName.黄灯输出, false, true, 0);
  305. //暂停-》继续
  306. if (currProcessIndex >= 0 && currentPT == CurrentPTEnum.Moving && currentState == CurrentStateEnum.等待启动)
  307. {
  308. AddTextEvent("启动", $"暂停 -> 继续 当前工序索引:{currProcessIndex + 1}");
  309. threadProcess = new System.Threading.Thread(() =>
  310. {
  311. int nextStepId = currProcessIndex;
  312. do
  313. {
  314. currentState = CurrentStateEnum.运行中;
  315. nextStepId = nextProcess(currProductModel, nextStepId);
  316. } while (nextStepId >= 0 && !isBreakProcessRun());
  317. //nextProcess(currProductModel, currProcessIndex);
  318. });
  319. threadProcess.IsBackground = true;
  320. threadProcess.Start();
  321. this.setButtonEnabled(this.tsbtnPause, true);
  322. this.setButtonEnabled(this.tsbtnStopNow, true);
  323. }
  324. else//开始/重新开始
  325. {
  326. //校正从复位-》运行,不会新启动
  327. resetUIValue();
  328. AddTextEvent("启动", "移动至上料位...");
  329. Task.Run(() => { loadOrderSNList(); });//加载SN
  330. gotoUpPT();
  331. this.Invoke(new System.Action(() =>
  332. {
  333. //新开始
  334. runStep();
  335. }));
  336. this.setButtonEnabled(this.tsbtnPause, false);
  337. this.setButtonEnabled(this.tsbtnStopNow, false);
  338. }
  339. this.setButtonEnabled(this.tsbtnStart, false);
  340. this.setButtonEnabled(this.tsbtnReset, false);
  341. this.setButtonEnabled(this.tsbtnGoDownPT, false);
  342. }
  343. /// <summary>
  344. /// 暂停
  345. /// </summary>
  346. /// <param name="buzzer">是否响蜂鸣</param>
  347. private void pauseCommand(bool buzzer = false)
  348. {
  349. //devContainer.io_output(CMDName.暂停按钮);
  350. //if (buzzer)
  351. //{
  352. // devContainer.io_output(CMDName.红灯输出);
  353. // devContainer.io_output(CMDName.蜂鸣器输出);
  354. //}
  355. //else
  356. // devContainer.io_output(CMDName.黄灯输出);
  357. devContainer.io_output(CMDName.启动按钮, false, true, 0);
  358. //devContainer.io_output(CMDName.绿灯输出, false, true, 0);
  359. this.setButtonEnabled(this.tsbtnWarning, true);
  360. this.setButtonEnabled(this.tsbtnGoDownPT, false);
  361. this.setButtonEnabled(this.tsbtnStart, false);
  362. this.setButtonEnabled(this.tsbtnPause, false);
  363. this.setButtonEnabled(this.tsbtnStopNow, false);
  364. this.setButtonEnabled(this.tsbtnReset, false);
  365. AddTextEvent("暂停", $"当前工序索引:{currProcessIndex + 1}", WarningEnum.Low);
  366. }
  367. /// <summary>
  368. /// 急停
  369. /// </summary>
  370. private void stopNowCommand()
  371. {
  372. if (!devContainer.state)
  373. {
  374. this.setButtonEnabled(this.tsbtnStopNow, false);
  375. return;
  376. }
  377. //devContainer.io_output(CMDName.Y轴复位输出, false, true, 0);
  378. //devContainer.io_output(CMDName.红灯输出);
  379. //if (!this.disableBuzzer) devContainer.io_output(CMDName.蜂鸣器输出);
  380. //devContainer.io_output(CMDName.暂停按钮, false, true, 0);
  381. //devContainer.io_output(CMDName.黄灯输出, false, true, 0);
  382. devContainer.io_output(CMDName.启动按钮, false, true, 0);
  383. //devContainer.io_output(CMDName.绿灯输出, false, true, 0);
  384. this.setButtonEnabled(this.tsbtnWarning, true);
  385. this.setButtonEnabled(this.tsbtnGoDownPT, false);
  386. this.setButtonEnabled(this.tsbtnStart, false);
  387. this.setButtonEnabled(this.tsbtnPause, false);
  388. this.setButtonEnabled(this.tsbtnStopNow, false);
  389. this.setButtonEnabled(this.tsbtnReset, false);
  390. if(currentState== CurrentStateEnum.运行中)
  391. AddTextEvent("急停", $"当前工序索引:{currProcessIndex + 1}", WarningEnum.High);
  392. else
  393. AddTextEvent("急停", $"已急停,请人工处理。", WarningEnum.High);
  394. }
  395. private bool reseting = false;
  396. private void resetCommand()
  397. {
  398. currentState = CurrentStateEnum.等待复位;
  399. warningLevel = WarningEnum.Normal;
  400. currentPT = CurrentPTEnum.InitPT;
  401. this.Invoke(new System.Action(() =>
  402. {
  403. this.tsbtnWarning.Enabled = this.tsbtnGoDownPT.Enabled = this.tsbtnStart.Enabled
  404. = this.tsbtnStopNow.Enabled = this.tsbtnPause.Enabled = this.tsbtnReset.Enabled
  405. = this.gpbXYAxis.Enabled = gpbZAxis.Enabled = false;
  406. }));
  407. try
  408. {
  409. if (devContainer.state && !reseting)
  410. {
  411. reseting = true;
  412. resetUIValue();
  413. AddTextEvent("复位", $"设备复位中...");
  414. this.setButtonEnabled(this.tsbtnReset, false);
  415. if ((AxisState)devContainer.devAxis.AxState[0] == AxisState.STA_AX_EXT_JOG) devContainer.devAxis.closeJogMode(0);//关闭jog时自动停止
  416. if ((AxisState)devContainer.devAxis.AxState[1] == AxisState.STA_AX_EXT_JOG) devContainer.devAxis.closeJogMode(1);//关闭jog时自动停止
  417. // I/O reset后,输出默认状态
  418. AddTextEvent("复位", $"I/O复位中...");
  419. if (!devContainer.devIOCard.reset())
  420. {
  421. AddTextEvent("复位", "I/O板卡复位失败!", WarningEnum.High);
  422. return;
  423. }
  424. if (!devContainer.io_output(CMDName.IO默认输出))
  425. {
  426. //AddTextEvent("复位", "I/O板卡复位默认值失败!", WarningEnum.High);
  427. //return;
  428. }
  429. //板卡复位输出灯
  430. //devContainer.io_output(CMDName.复位按钮);
  431. devContainer.io_output(CMDName.复位按钮, true);//闪
  432. //goto ORG
  433. AddTextEvent("复位", $"轴正在回原点...");
  434. devContainer.devAxis.closeJogMode();
  435. devContainer.devAxis.resetAxisState(-1);//reset state
  436. //AddTextEvent("复位", $"重置轴状态...");
  437. for (int i = 0; i < Config.Axis_HomeMode.Length; i++)
  438. {
  439. //到起始位速度使用回HOME速度
  440. devContainer.devAxis.setAxisVelParam((double)Config.Axis_HomeVelLow[i], (double)Config.Axis_HomeVelHigh[i],
  441. (double)Config.Axis_HomeAcc[i], (double)Config.Axis_HomeDec[i], i);
  442. //devContainer.devAxis.setAxisVelParam(40000,200000,5000000, 5000000,i,true);
  443. devContainer.devAxis.home(i, (uint)Config.Axis_HomeMode[i], (uint)Config.Axis_HomeDir[i]);
  444. }
  445. AddTextEvent("复位", $"等待轴状态完成...");
  446. while (!devContainer.devAxis.isReady())
  447. {
  448. if (!devContainer.state || currentState != CurrentStateEnum.等待复位)
  449. {
  450. AddTextEvent("复位", $"当前状态:" + ((CurrentStateEnum)currentState).ToString());
  451. return;
  452. }
  453. //AddTextEvent("复位", $"轴0状态:"+ ((AxisState)devContainer.devAxis.AxState[0]).ToString());
  454. //AddTextEvent("复位", $"轴1状态:" + ((AxisState)devContainer.devAxis.AxState[1]).ToString());
  455. //AddTextEvent("复位", $"轴2状态:" + ((AxisState)devContainer.devAxis.AxState[2]).ToString());
  456. //AddTextEvent("复位", $"轴3状态:" + ((AxisState)devContainer.devAxis.AxState[3]).ToString());
  457. Thread.Sleep(1000);
  458. //Application.DoEvents();
  459. }
  460. //
  461. if (devContainer.devAxis.isError())
  462. throw new Exception("轴回原点失败!");
  463. //
  464. //goto InitPT
  465. AddTextEvent("复位", $"轴回原点完成,回到初始位...");
  466. JArray arrPT = Config.joPTSetting.Value<JArray>("initPT");
  467. for (int i = 0; i < arrPT.Count; i++)
  468. {
  469. if (!devContainer.state || currentState != CurrentStateEnum.等待复位)
  470. return;
  471. AddTextEvent($"复位", $"轴{i}准备运动至初始位:{(double)arrPT[i]}(当前轴状态:{((AxisState)devContainer.devAxis.AxState[i]).ToString()})...");
  472. devContainer.devAxis.move_ptp(i, (double)arrPT[i], AxMoveMode.MODE1_Abs);
  473. }
  474. while (!devContainer.devAxis.isReady())
  475. {
  476. if (!devContainer.state || warningLevel != WarningEnum.Normal)
  477. return;
  478. Thread.Sleep(100);
  479. //Application.DoEvents();
  480. }
  481. if (devContainer.devAxis.isError())
  482. throw new Exception("轴移动至初始位失败!");
  483. //
  484. this.setButtonEnabled(this.tsbtnReset, true);
  485. this.setButtonEnabled(this.tsbtnStart, true);
  486. this.setButtonEnabled(this.tsbtnStopNow, true);
  487. this.setButtonEnabled(this.tsbtnPause, false);
  488. this.setButtonEnabled(this.tsbtnGoDownPT, false);
  489. this.setButtonEnabled(this.tsbtnWarning, false);
  490. this.setButtonEnabled(this.cbxSN, false);
  491. this.Invoke(new System.Action(() =>
  492. {//根据UI上是否勾选打开激光
  493. chkLaser_CheckedChanged(null, null);
  494. }));
  495. //devContainer.io_output(CMDName.复位按钮, false, true, 0);//熄灭
  496. devContainer.io_output(CMDName.复位按钮);//长亮
  497. currentPT = CurrentPTEnum.InitPT;
  498. currentState = CurrentStateEnum.等待启动;
  499. AddTextEvent("复位", $"复位完成。");
  500. }
  501. else
  502. {
  503. AddTextEvent("复位", "非可复位状态,请先停止后再复位!", WarningEnum.High);
  504. }
  505. }
  506. catch (Exception ex)
  507. {
  508. AddTextEvent("复位", "复位失败 Err:" + ex.Message, WarningEnum.High);
  509. warning(WarningEnum.High, true);
  510. }
  511. finally
  512. {
  513. reseting = false;
  514. }
  515. }
  516. /// <summary>
  517. /// 上料
  518. /// </summary>
  519. private void gotoUpPT()
  520. {
  521. try
  522. {
  523. JArray arrPT = Config.joPTSetting.Value<JArray>("upPT");
  524. for (int i = 0; i < arrPT.Count; i++)
  525. {
  526. if (!devContainer.state || warningLevel != WarningEnum.Normal)
  527. return;
  528. AddTextEvent($"上料", $"轴{i}准备运动至上料位:{(double)arrPT[i]}(当前轴状态:{((AxisState)devContainer.devAxis.AxState[i]).ToString()})...");
  529. devContainer.devAxis.move_ptp(i, (double)arrPT[i], AxMoveMode.MODE1_Abs);
  530. }
  531. while (!devContainer.devAxis.isReady())
  532. {
  533. if (!devContainer.state || warningLevel != WarningEnum.Normal)
  534. return;
  535. Thread.Sleep(100);
  536. }
  537. if (devContainer.devAxis.isError())
  538. throw new Exception("轴移动至上料位失败!");
  539. //
  540. currentPT = CurrentPTEnum.UpPT;
  541. currentState = CurrentStateEnum.等待扫码;
  542. this.setButtonEnabled(cbxSN, true);
  543. AddTextEvent($"上料", "到达上料位!");
  544. }
  545. catch (Exception ex)
  546. {
  547. AddTextEvent("上料", "上料初始失败 Err:" + ex.Message, WarningEnum.High);
  548. warning(WarningEnum.High);
  549. }
  550. }
  551. /// <summary>
  552. /// 下料(暂当完成)
  553. /// </summary>
  554. private void gotoDownPT()
  555. {
  556. try
  557. {
  558. if (!devContainer.state || warningLevel != WarningEnum.Normal)
  559. return;
  560. if (!devContainer.devAxis.isReady())
  561. {
  562. AddTextEvent("下料失败", "轴状态异常!", WarningEnum.Low);
  563. return;
  564. }
  565. if (currentState != CurrentStateEnum.打标中 && currentState != CurrentStateEnum.等待启动 && currentState != CurrentStateEnum.自动流程结束)
  566. {
  567. AddTextEvent($"下料", $"非可下料状态:{currentState.ToString()}");
  568. return;
  569. }
  570. currentState = CurrentStateEnum.下料中;
  571. JArray arrPT = Config.joPTSetting.Value<JArray>("downPT");
  572. for (int i = 0; i < arrPT.Count; i++)
  573. {
  574. if (!devContainer.state || warningLevel != WarningEnum.Normal || currentState != CurrentStateEnum.下料中)
  575. return;
  576. AddTextEvent($"下料", $"轴{i}准备运动至下料位:{(double)arrPT[i]}(当前轴状态:{((AxisState)devContainer.devAxis.AxState[i]).ToString()})...");
  577. devContainer.devAxis.move_ptp(i, (double)arrPT[i], AxMoveMode.MODE1_Abs);
  578. }
  579. while (!devContainer.devAxis.isReady())
  580. {
  581. if (!devContainer.state || warningLevel != WarningEnum.Normal || currentState != CurrentStateEnum.下料中)
  582. return;
  583. Thread.Sleep(100);
  584. }
  585. if (devContainer.devAxis.isError())
  586. throw new Exception("轴移动至下料位失败!");
  587. //
  588. currentPT = CurrentPTEnum.DownPT;
  589. currentState = CurrentStateEnum.等待启动;
  590. devContainer.io_output(CMDName.启动按钮, false, true, 0);
  591. devContainer.devLight.setDigitalValue(1, 0);//关闭上光源
  592. devContainer.devLight.setDigitalValue(2, 0);//关闭下光源
  593. this.Invoke(new System.Action(() =>
  594. {
  595. this.chkLaser.Checked = false;
  596. this.gpbXYAxis.Enabled = gpbZAxis.Enabled = false;
  597. }));
  598. setButtonEnabled(tsbtnStart, true);
  599. setButtonEnabled(tsbtnGoDownPT, false);
  600. AddTextEvent($"下料", "下料完成!");
  601. //更新指定列
  602. //2023-10-31 加入异常情况
  603. FrmRepairInfo frmInfo = new FrmRepairInfo();
  604. DialogResult dr = frmInfo.ShowDialog();
  605. if (svcOrder.Update(it => new Order() {
  606. State = dr == DialogResult.OK? 10 :5 ,
  607. Abnormalities = frmInfo.RepairInfo,
  608. RepairCode = Config.loginUser.Code
  609. }, it => it.Id == OrderId))
  610. AddTextEvent($"检测结束", $"保存检测结果成功。");
  611. else
  612. AddTextEvent($"检测结束", $"保存检测结果失败!",WarningEnum.High);
  613. }
  614. catch (Exception ex)
  615. {
  616. AddTextEvent("下料", "下料失败 Err:" + ex.Message, WarningEnum.High);
  617. warning(WarningEnum.High);
  618. }
  619. }
  620. private void openLowerLight()//下光源
  621. {
  622. var value = devContainer.devLight.getDigitalValue(2);
  623. devContainer.devLight.setDigitalValue(2, value == 0 ? 255 : 0);
  624. }
  625. private void setButtonEnabled(ToolStripButton button, bool Enabled)
  626. {
  627. this.Invoke(new System.Action(() =>
  628. {
  629. button.Enabled = Enabled;
  630. }));
  631. }
  632. private void setButtonEnabled(ToolStripMenuItem button, bool Enabled)
  633. {
  634. this.Invoke(new System.Action(() =>
  635. {
  636. button.Enabled = Enabled;
  637. }));
  638. }
  639. private void setButtonEnabled(Control button, bool Enabled)
  640. {
  641. this.Invoke(new System.Action(() =>
  642. {
  643. button.Enabled = Enabled;
  644. }));
  645. }
  646. #endregion
  647. #region 自动流程 nextProcess
  648. /// <summary>
  649. /// 中断工序运行
  650. /// </summary>
  651. /// <returns></returns>
  652. private bool isBreakProcessRun()
  653. {
  654. return warningLevel != WarningEnum.Normal || currentState != CurrentStateEnum.运行中;
  655. }
  656. private void runStep()
  657. {
  658. sizeBmpNum = sizeBmpNumResult = 0;
  659. AddTextEvent("启动", "等待网版编码扫码...");
  660. if (devContainer.devCodeScanner != null)
  661. {
  662. devContainer.devCodeScanner.stop();
  663. devContainer.devCodeScanner = null;
  664. }
  665. devContainer.devCodeScanner = new CodeScannerDev();
  666. if (!devContainer.devCodeScanner.start())
  667. {
  668. AddTextEvent("扫码枪", "扫码枪初始化失败!");
  669. return;
  670. }
  671. devContainer.devCodeScanner.ScanerEvent = (code) =>
  672. {
  673. if (devContainer.devCodeScanner.isLock ||!devContainer.state
  674. || currentState != CurrentStateEnum.等待扫码 || string.IsNullOrWhiteSpace(code) )
  675. return;
  676. devContainer.devCodeScanner.isLock = true;
  677. Thread threadtest = new System.Threading.Thread(() =>
  678. {
  679. try
  680. {
  681. //注:需要重复输入SN时不能在此释放
  682. //devContainer.devCodeScanner.stop();
  683. //devContainer.devCodeScanner = null;
  684. //
  685. AddTextEvent("扫码枪", $"开始读取网版编码:{code} 数据...");
  686. var modOrder = svcOrder.GetModelNav(code);//from sn
  687. //AddTextEvent("扫码枪", $"读取网版编码:{code}DB数据完成");
  688. string modeState = "";
  689. if (modOrder == null)
  690. AddTextEvent("扫码枪", $"网版编码{code}不存在!");
  691. if (modOrder.State == 5)
  692. {
  693. modeState = $"网版编码{code}已被检测!";
  694. AddTextEvent("扫码枪", $"网版编码{code}已被检测!");
  695. loadOrderSNList();
  696. }
  697. else if (modOrder.State == 10)
  698. {
  699. modeState = $"网版编码{code}已被检测, 并且异常!";
  700. AddTextEvent("扫码枪", $"网版编码{code}已被检测, 并且异常!");
  701. loadOrderSNList();
  702. }
  703. if(!string.IsNullOrEmpty(modeState))
  704. {
  705. if(DialogResult.No == MessageBox.Show(modeState + "是否重新检测!", "网版已被检测", MessageBoxButtons.YesNo, MessageBoxIcon.Information))
  706. {
  707. return;
  708. }
  709. }
  710. //2023-10-20
  711. //else if (modOrder.ProductInfo == null)
  712. if (modOrder.ProductInfo == null)
  713. AddTextEvent("扫码枪", $"网版编码:{code}对应产品信息已不存在!");
  714. else if (modOrder.DefectCount < 1)
  715. AddTextEvent("扫码枪", $"网版编码:{code}没有缺陷!");
  716. //else if (string.IsNullOrWhiteSpace(modOrder.MarkData))
  717. // AddTextEvent("扫码枪", $"产品(网版编码:{code})在主机台未保存原始Mark点!");
  718. else if (modOrder.ProductInfo.AssistStepInfo == null
  719. || modOrder.ProductInfo.AssistStepInfo.ProcessList.Count < 1)
  720. AddTextEvent("扫码枪", $"产品({modOrder.ProductInfo.Name})未配置检测流程!");
  721. else
  722. {
  723. if (string.IsNullOrWhiteSpace(modOrder.MarkData))
  724. {
  725. AddTextEvent("扫码枪", $"产品(网版编码:{code})在主机台未保存原始Mark点!");
  726. modOrder.MarkData = "[0,0,0,0,0,0,0,0]";
  727. }
  728. else
  729. AddTextEvent("主机台", $"主机台Mark数据:{modOrder.MarkData}");
  730. currProductMarkList = JArray.Parse(modOrder.MarkData);
  731. if (currProductMarkList.Count < 8)
  732. {
  733. AddTextEvent("主机台", $"产品(网版编码:{code})在主机台原始Mark点数量错误!");
  734. return;
  735. }
  736. //异步读取
  737. JObject parm = new JObject()
  738. {
  739. {"date",modOrder.CreateTime.ToString("yyyyMMdd") },
  740. {"sn",code }
  741. };
  742. Task.Run(() => loadDefectInfo(parm));
  743. //
  744. devContainer.devCodeScanner.stop();
  745. devContainer.devCodeScanner = null;
  746. currentState = CurrentStateEnum.运行中;
  747. currentPT = CurrentPTEnum.Moving;
  748. currProductModel = modOrder.ProductInfo;
  749. AddTextEvent("扫码枪", $"网版编码:{code}({currProductModel.Name} {currProductModel.Spec} [{currProductModel.Code}])");
  750. this.Invoke(new System.Action(() =>
  751. {
  752. this.cbxSN.Enabled = false;
  753. this.txtBatchId.Text = modOrder.BatchId.ToString();
  754. this.txtProductName.Text = currProductModel.Name;
  755. this.txtProductCode.Text = currProductModel.Code;
  756. this.txtCreateTime.Text = modOrder.CreateTime.ToString("yyyy-MM-dd HH:mm");
  757. //this.dgvProcess.DataSource = new BindingSource(currProductModel.StepInfo.ProcessList, null);
  758. devContainer.libFor.clear();
  759. devContainer.libIF.clear();
  760. }));
  761. //
  762. this.SN = code;
  763. this.OrderId = modOrder.Id;
  764. this.setButtonEnabled(this.tsbtnPause, true);
  765. this.setButtonEnabled(this.tsbtnStopNow, true);
  766. devContainer.devLight.setDigitalValue(2, 255);//下光源
  767. int nextStepId = 0;
  768. do
  769. {
  770. nextStepId = nextProcess(currProductModel, nextStepId);
  771. } while (nextStepId >= 0 && !isBreakProcessRun());
  772. }
  773. }
  774. catch (Exception ex)
  775. {
  776. AddTextEvent("扫码枪", $"读取网版编码信息失败:{ex.Message}");
  777. }
  778. finally
  779. {
  780. if (devContainer.devCodeScanner != null)
  781. devContainer.devCodeScanner.isLock = false;
  782. }
  783. });
  784. threadtest.IsBackground = true;
  785. threadtest.Start();
  786. };
  787. }
  788. private void loadDefectInfo(object parm)
  789. {
  790. try
  791. {
  792. JObject req = (JObject)parm;
  793. currDefectIndex = 0;
  794. defectList.Clear();
  795. defectInfoDir.Clear();
  796. defectBmpsDir.Clear();
  797. //从主机台取缺陷文件名列表和JSON数组
  798. var obj = WebApi.getDefectFromSN(req);
  799. if (obj.Value<int>("code") != 200)
  800. throw new Exception(obj.Value<string>("data"));
  801. //
  802. var defectInfo = obj.Value<JObject>("data"); //文件名列表(主机台已对文件名排序,这里不需再排序(主机台按各自index进行的排序,比对在缺陷文件名后面)
  803. if (defectInfo.Count < 1)
  804. throw new Exception("主机台缺陷文件已不存在!");
  805. //string date = req.Value<string>("date");
  806. //string sn = req.Value<string>("sn");
  807. getDefectBmpList(req, defectInfo);
  808. }
  809. catch (Exception ex)
  810. {
  811. AddTextEvent("网络访问",$"{ex.Message}",WarningEnum.High);
  812. warning(WarningEnum.High);
  813. }
  814. }
  815. /// <summary>
  816. /// 通过文件名列表取各文件名对应BMP
  817. /// </summary>
  818. /// <param name="req"></param>
  819. /// <param name="defectInfo">文件名列表</param>
  820. private void getDefectBmpList(JObject req, JObject defectInfo)
  821. {
  822. int liStep = 0;
  823. try
  824. {
  825. #region 这里转换绑定没实际用处,只是为了提前显示列表
  826. foreach (var kv in defectInfo)
  827. {
  828. defectInfoDir.Add(kv.Key, JsonConvert.DeserializeObject<List<List<string>>>(kv.Value.ToString()));
  829. //
  830. //["4","3.9","-0.8","dk","0.39"],["index","X","Y","缺陷类型","缺陷的置信度"]
  831. JArray arr = kv.Value as JArray;//二维数组
  832. AddTextEvent("主机台", $"缺陷大项:{kv.Key},含小项:{arr.Count}.");
  833. foreach (JArray arr2 in arr) {
  834. var obj = new DefectStruct();
  835. obj.Key = kv.Key;
  836. obj.Index = Convert.ToInt32(arr2[0].ToString());
  837. obj.X = Convert.ToDouble(arr2[1].ToString());
  838. obj.Y = Convert.ToDouble(arr2[2].ToString());
  839. obj.DefectName = Config.getDefectName(arr2[3].ToString());
  840. obj.DefectCC = Convert.ToDouble(arr2[4].ToString());
  841. defectList.Add(obj);
  842. }
  843. }
  844. this.Invoke(new System.Action(() =>
  845. {
  846. //注:这样绑定List中的对象必需得用{get;set;}方式定义属性,否则单独格为空内容
  847. AddTextEvent("主机台", $"准备显示缺陷列表,共{defectList.Count}项.");
  848. this.dgvProcess.DataSource = new BindingSource(defectList, null);
  849. AddTextEvent("主机台", $"显示缺陷列表完成.");
  850. this.gpbDefectList.Text = $"缺陷明细({defectList.Count}条)";
  851. //2023-11-1 图纸对比缺陷标红
  852. for (int i = 0; i < defectList.Count; i++)
  853. {
  854. string defName = (string)this.dgvProcess.Rows[i].Cells["colDefectName"].Value;
  855. if ((defName == Config.getDefectName("ds"))||((defName == Config.getDefectName("yx"))))
  856. this.dgvProcess.Rows[i].DefaultCellStyle.BackColor = Color.Red;
  857. }
  858. }));
  859. #endregion
  860. req.Add("file_name", "");
  861. liStep = 1;
  862. bool first = true;
  863. int index = 1;
  864. foreach (var kv in defectInfo)
  865. {
  866. req["file_name"] = kv.Key;
  867. var obj = WebApi.getDefectBmpBase64(req);
  868. if (!devContainer.state || warningLevel == WarningEnum.High ||
  869. (currentState != CurrentStateEnum.运行中 && currentState != CurrentStateEnum.暂停 && currentState != CurrentStateEnum.等待启动 && currentState != CurrentStateEnum.打标中))
  870. return;
  871. if (obj.Value<int>("code") != 200)
  872. throw new Exception(obj.Value<string>("data"));
  873. Bitmap bmp = new Bitmap(new MemoryStream(Convert.FromBase64String(obj.Value<string>("data"))));
  874. defectBmpsDir.Add(kv.Key, bmp);
  875. AddTextEvent("网络访问", $"已读取第{index++}/{defectInfo.Count}张缺陷图片;");
  876. if (first)
  877. {
  878. first = false;
  879. this.Invoke(new System.Action(() =>
  880. {
  881. this.reloadPic(bmp,null,null);
  882. pictureBox1.Tag = kv.Key;
  883. }));
  884. }
  885. }
  886. }
  887. catch (Exception ex)
  888. {
  889. if (liStep == 0)
  890. {
  891. AddTextEvent("网络访问", $"解析主机缺陷报文失败:{ex.Message}",WarningEnum.High);
  892. warning(WarningEnum.High);
  893. }
  894. else
  895. AddTextEvent("网络访问", $"读取主机台缺陷Bmp图片失败:{ex.Message}");
  896. }
  897. }
  898. private void convert2LocXY()
  899. {
  900. //AddTextEvent($"缺陷项", $"转换缺陷项坐标值...");
  901. // public string Key;
  902. //public string Key0;//index
  903. //public string Key1;//X
  904. //public string Key2;//Y
  905. //public string Key3;//缺陷类型
  906. //public string Key4;//缺陷的置信度
  907. currDefectIndex = 0;
  908. defectList.Clear();
  909. double X, Y;
  910. int MainIndex;
  911. foreach (var item in defectInfoDir)
  912. {
  913. //Key : Defect_SN{order.SN}_I{res.index}_X{res.Xmm}_Y{res.Ymm}_C{res.defectCount}
  914. string[] str = item.Key.Split('_');
  915. MainIndex = Convert.ToInt32(str[2].Substring(1));
  916. X = Convert.ToDouble(str[3].Substring(1));
  917. Y = Convert.ToDouble(str[4].Substring(1));
  918. AddTextEvent("主机台", $"转换前,缺陷大项:{item.Key},含小项:{item.Value.Count}.");
  919. var arr = yolo.ImageXY2RepairTable(item.Value, X, Y, Config.SizeRepairTablePath);
  920. AddTextEvent("主机台", $"转换后,缺陷大项:{item.Key},含小项:{arr.Count}.");
  921. int i = 0;
  922. foreach (var arr2 in arr)
  923. {
  924. var obj = new DefectStruct();
  925. obj.Key = item.Key;
  926. obj.CurrIndex = i++;
  927. obj.MainIndex = MainIndex;
  928. obj.MainX = X;
  929. obj.MainY = Y;
  930. obj.Index = Convert.ToInt32(arr2[0].ToString());
  931. obj.X = Convert.ToDouble(arr2[1].ToString());
  932. obj.Y = Convert.ToDouble(arr2[2].ToString());
  933. obj.DefectName = Config.getDefectName(arr2[3].ToString());
  934. obj.DefectCC = Convert.ToDouble(arr2[4].ToString());
  935. defectList.Add(obj);
  936. }
  937. }
  938. this.Invoke(new System.Action(() =>
  939. {
  940. this.dgvProcess.DataSource = null;
  941. //注:这样绑定List中的对象必需得用{get;set;}方式定义属性,否则单独格为空内容
  942. this.dgvProcess.DataSource = new BindingSource(defectList, null);
  943. this.gpbDefectList.Text = $"缺陷明细({defectList.Count}条)";
  944. }));
  945. gotoDefctListIndex(currDefectIndex);
  946. }
  947. private void gotoDefctListIndex(int index,int preIndex=-1)
  948. {
  949. try
  950. {
  951. AddTextEvent($"缺陷项", $"移至缺陷项:{index + 1}...");
  952. this.Invoke(new System.Action(() =>
  953. {
  954. string key = defectList[index].Key;
  955. if (defectBmpsDir.ContainsKey(key))
  956. {
  957. if (pictureBox1.Tag == null || pictureBox1.Tag.ToString() != key)
  958. {
  959. //reloadPic(defectBmpsDir[key], defectInfoDir[key], defectList[index]);
  960. pictureBox1.Tag = key;
  961. }
  962. reloadPic(defectBmpsDir[key], defectInfoDir[key], defectList[index]);
  963. }
  964. else
  965. AddTextEvent($"缺陷项", $"缺陷图:{defectList[index].Key}还未传输完成!");
  966. if (preIndex > -1)
  967. this.dgvProcess.Rows[preIndex].DefaultCellStyle.BackColor = Color.White;
  968. this.dgvProcess.Rows[index].DefaultCellStyle.BackColor = Color.LightGreen;
  969. this.dgvProcess.Rows[index].Selected = true;
  970. this.dgvProcess.CurrentCell = this.dgvProcess.Rows[index].Cells["colResult"];
  971. this.dgvProcess.Rows[index].Cells["colResult"].Value = "已检";
  972. }));
  973. while (!devContainer.devAxis.isReady(0)) Thread.Sleep(100);
  974. devContainer.devAxis.move_ptp(0, defectList[index].X, AxMoveMode.MODE1_Abs);
  975. while (!devContainer.devAxis.isReady(1)) Thread.Sleep(100);
  976. devContainer.devAxis.move_ptp(1, defectList[index].Y, AxMoveMode.MODE1_Abs);
  977. AddTextEvent($"缺陷项", $"移动完成,当前缺陷项({index + 1})坐标:X{defectList[index].X},Y{defectList[index].Y}");
  978. }
  979. catch (Exception ex)
  980. {
  981. AddTextEvent("缺陷项", "轴移动失败:" + ex.Message, WarningEnum.High);
  982. warning(WarningEnum.High, true);
  983. }
  984. }
  985. private void gotoNextPic()
  986. {
  987. if (currDefectIndex>= defectList.Count-1) return;
  988. this.Invoke(new System.Action(() =>
  989. {
  990. for(int i= currDefectIndex+1;i< defectList.Count; i++)
  991. {
  992. if (this.pictureBox1.Tag == null || this.pictureBox1.Tag.ToString() != defectList[i].Key)
  993. {
  994. AddTextEvent($"缺陷项", $"移至下张图:{i+1}...");
  995. int preIndex = currDefectIndex;
  996. currDefectIndex = i;
  997. gotoDefctListIndex(currDefectIndex, preIndex);
  998. return;
  999. }
  1000. }
  1001. }));
  1002. }
  1003. private void gotoPrePic()
  1004. {
  1005. if (currDefectIndex < 1) return;
  1006. this.Invoke(new System.Action(() =>
  1007. {
  1008. if (this.pictureBox1.Tag == null) return;
  1009. for (int i = currDefectIndex-1; i >=0; i--)
  1010. {
  1011. if (this.pictureBox1.Tag.ToString() != defectList[i].Key)
  1012. {
  1013. AddTextEvent($"缺陷项", $"移至上张图:{i + 1}...");
  1014. int preIndex = currDefectIndex;
  1015. currDefectIndex = i;
  1016. gotoDefctListIndex(currDefectIndex, preIndex);
  1017. return;
  1018. }
  1019. }
  1020. }));
  1021. }
  1022. private class DefectStruct
  1023. {
  1024. //Defect_{order.SN}_{res.index}_X{res.Xmm}_Y{res.Ymm}
  1025. public string Key { get; set; }
  1026. public int CurrIndex { get; set; }//当前缺陷在本大图中的索引0-n
  1027. public int MainIndex { get; set; }//大图
  1028. public double MainX { get; set; }//大图X 大相机拍照时原始X,Y轴坐标
  1029. public double MainY { get; set; }//大图X
  1030. //["4","3.9","-0.8","dk","0.39"],["index","X","Y","缺陷类型","缺陷的置信度"]
  1031. public int Index { get; set; }
  1032. public double X { get; set; }
  1033. public double Y { get; set; }
  1034. public string DefectName { get; set; }//缺陷类型
  1035. public double DefectCC { get; set; }//缺陷的置信度
  1036. //2023-10-30 修复情况
  1037. public string Restoratory { get; set; }
  1038. }
  1039. private double[] convert(JArray data)
  1040. {
  1041. double[] result = new double[data.Count];
  1042. for (int i = 0; i < data.Count; i++)
  1043. result[i]=Convert.ToDouble(data[i]);
  1044. return result;
  1045. }
  1046. /// <summary>
  1047. /// 工序循环
  1048. /// </summary>
  1049. /// <param name="model"></param>
  1050. /// <param name="stepIndex">0-n</param>
  1051. /// <returns>大于等于0正常工序; -1:结束 -2:异常</returns>
  1052. private int nextProcess(Models.Product model, int stepIndex)
  1053. {
  1054. try
  1055. {
  1056. //记录当前index
  1057. this.currProcessIndex = stepIndex;
  1058. //this.Invoke(new System.Action(() =>
  1059. //{
  1060. // try
  1061. // {
  1062. // this.dgvProcess.Rows[stepIndex].Selected = true;
  1063. // dgvProcess.CurrentCell = dgvProcess.Rows[stepIndex].Cells[1];
  1064. // }
  1065. // catch { }
  1066. //}));
  1067. lock (myLock)
  1068. {
  1069. if (isBreakProcessRun())
  1070. return stepIndex;
  1071. }
  1072. var processList = model.AssistStepInfo.ProcessList;
  1073. var processInfo = processList[stepIndex];
  1074. string processName = processInfo.ProcessName;
  1075. //AddTextEvent($"{stepIndex + 1}-{processName}", $"工序开始...");
  1076. string jsonParams = null;//配方
  1077. if (model.ProductProcessList != null && model.ProductProcessList.Count > 0)//使用产品配方
  1078. {
  1079. ProductProcess productProcessParams = model.ProductProcessList.First(m => m.ProcessCode == processInfo.ProcessCode);
  1080. if (productProcessParams != null)
  1081. {
  1082. jsonParams = productProcessParams.ProcessParams;
  1083. AddTextEvent($"{stepIndex + 1}-{processName}", $"使用产品专用配方:{jsonParams}");
  1084. }
  1085. }
  1086. if (jsonParams == null)//使用流程默认配方
  1087. {
  1088. jsonParams = processInfo.ProcessParams;
  1089. AddTextEvent($"{stepIndex + 1}-{processName}", $"使用流程默认配方:{jsonParams}");
  1090. }
  1091. //
  1092. JObject processParam = JObject.Parse(jsonParams);
  1093. if (!processParam.ContainsKey("Disable") || !processParam.Value<bool>("Disable"))
  1094. {
  1095. AutoResetEvent endEvent;
  1096. uint sleepPre = processParam.Value<uint>("SleepPre");
  1097. uint sleepLater = processParam.Value<uint>("SleepLater");
  1098. if (sleepPre > 0)
  1099. Thread.Sleep((int)sleepPre);
  1100. double limitThresholdVal, lowerThresholdVal;
  1101. //======Switch 工序类型
  1102. int liStatocStepIndex = stepIndex;
  1103. switch (processInfo.ProcessCode)
  1104. {
  1105. case "IOCard":
  1106. #region
  1107. var direction = (IODirectionEnum)processParam.Value<int>("Direction");
  1108. if (direction == IODirectionEnum.输入 || direction == IODirectionEnum.输入输出)
  1109. {
  1110. uint IN_Waiting_Timeout = processParam.Value<uint>("IN_Waiting_Timeout");
  1111. AddTextEvent($"{stepIndex + 1}-{processName}", $"等待I/O输入信号{(IN_Waiting_Timeout > 0 ? $"(超时时长: {IN_Waiting_Timeout})" : "...")}");
  1112. string[] inValue = processParam.Value<JArray>("IN_OP_SHOW").ToObject<List<string>>().ToArray();
  1113. uint inWaitingTime = 0;
  1114. while (true)
  1115. {
  1116. if (isBreakProcessRun())
  1117. return stepIndex;
  1118. if (Util.compareIOInput(inValue, devContainer.devIOCard.DIData))
  1119. break;
  1120. Thread.Sleep(10);
  1121. inWaitingTime += 10;
  1122. if (IN_Waiting_Timeout > 0 && inWaitingTime >= IN_Waiting_Timeout)
  1123. {
  1124. AddTextEvent($"{stepIndex + 1}-{processName}", $"输入等待超时告警!", WarningEnum.High);
  1125. warning(WarningEnum.Low);//暂停
  1126. return stepIndex;
  1127. }
  1128. }
  1129. AddTextEvent($"{stepIndex + 1}-{processName}", $"I/O输入信号对比完成!");
  1130. }
  1131. if (direction == IODirectionEnum.输出 || direction == IODirectionEnum.输入输出)
  1132. devContainer.io_output($"{stepIndex + 1}-{processName}", processParam);
  1133. #endregion
  1134. break;
  1135. case "Axis":
  1136. #region
  1137. bool asynRun = processParam.Value<bool>("AsynRun");//异步
  1138. int AxisIndex = processParam.Value<int>("AxisIndex");
  1139. int DeviceType = processParam.Value<int>("DeviceType");
  1140. double VelLow = processParam.Value<double>("VelLow");
  1141. double VelHigh = processParam.Value<double>("VelHigh");
  1142. double Acc = processParam.Value<double>("Acc");
  1143. double Dec = processParam.Value<double>("Dec");
  1144. AxMoveMode MoveMode = (AxMoveMode)processParam.Value<int>("MoveMode");//绝对位置
  1145. double PPUValue = processParam.Value<double>("Value");
  1146. AddTextEvent($"{stepIndex + 1}-{processName}", $"轴{AxisIndex}准备({(MoveMode == AxMoveMode.MODE1_Abs ? "绝对" : "相对")})运动至{PPUValue}(当前轴状态:{((AxisState)devContainer.devAxis.AxState[AxisIndex]).ToString()})...");
  1147. ////移动Axis前等待厚度传感器收回
  1148. //if (!Config.SkipHeight)
  1149. //{
  1150. // while (devContainer.devHeight.getHeight() < (double)Math.Abs(Config.HeightDev_SafeValue))
  1151. // {
  1152. // if (isBreakProcessRun())
  1153. // return stepIndex;
  1154. // Thread.Sleep(10);
  1155. // }
  1156. //}
  1157. while (!devContainer.devAxis.isReady(AxisIndex))
  1158. {
  1159. Thread.Sleep(100);
  1160. if (isBreakProcessRun())
  1161. return stepIndex;
  1162. }
  1163. devContainer.devAxis.setAxisVelParam(VelLow, VelHigh, Acc, Dec, AxisIndex);
  1164. if (!devContainer.devAxis.move_ptp(AxisIndex, PPUValue, MoveMode))
  1165. {
  1166. AddTextEvent($"{stepIndex + 1}-{processName}", $"轴{AxisIndex}运动失败!", WarningEnum.Low);
  1167. warning(WarningEnum.Low);//终止
  1168. return stepIndex;
  1169. }
  1170. AddTextEvent($"{stepIndex + 1}-{processName}", $"等待轴{AxisIndex}运行完成...");
  1171. while (!asynRun && !devContainer.devAxis.isReady(AxisIndex))
  1172. {
  1173. Thread.Sleep(100);
  1174. if (isBreakProcessRun())
  1175. {
  1176. currProcessIndex = stepIndex + 1;
  1177. return stepIndex;
  1178. }
  1179. }
  1180. AddTextEvent($"{stepIndex + 1}-{processName}", $"轴{AxisIndex}运行完成,当前命令位置:{devContainer.devAxis.getCmdPos_mm(AxisIndex)},反馈位置:{devContainer.devAxis.getActualPos_mm(AxisIndex)}");
  1181. #endregion
  1182. break;
  1183. case "Light":
  1184. #region
  1185. if (Config.SkipLight)
  1186. {
  1187. AddTextEvent($"{stepIndex + 1}-{processName}", $"设备禁用,忽略此步骤!");
  1188. //setDgvContentCol(liStatocStepIndex, $"设备禁用,忽略此步骤!");
  1189. break;
  1190. }
  1191. int ChannelIndex = processParam.Value<int>("ChannelIndex"); //通道
  1192. int DigitalValue = processParam.Value<int>("DigitalValue"); //亮度
  1193. int nowDiaitalValue = devContainer.devLight.getDigitalValue(ChannelIndex);
  1194. AddTextEvent($"{stepIndex + 1}-{processName}", $"通道{ChannelIndex}当前值:{nowDiaitalValue},准备更新值:{DigitalValue}...");
  1195. devContainer.devLight.setDigitalValue(ChannelIndex, DigitalValue);
  1196. nowDiaitalValue = devContainer.devLight.getDigitalValue(ChannelIndex);
  1197. AddTextEvent($"{stepIndex + 1}-{processName}", $"通道{ChannelIndex}更新后当前值:{nowDiaitalValue}。");
  1198. #endregion
  1199. break;
  1200. case "Scanner_CC":
  1201. #region
  1202. if (Config.SkipScannerCC)
  1203. {
  1204. AddTextEvent($"{stepIndex + 1}-{processName}", $"设备禁用,忽略此步骤!");
  1205. //setDgvContentCol(liStatocStepIndex, $"设备禁用,忽略此步骤!");
  1206. break;
  1207. }
  1208. while (!devContainer.devAxis.isReady())//因启用轴异步功能,使用前需等待
  1209. {
  1210. Thread.Sleep(100);
  1211. if (isBreakProcessRun())
  1212. {
  1213. //currProcessIndex = stepIndex;//本工序没执行,step不变
  1214. return stepIndex;
  1215. }
  1216. }
  1217. float ExposureTimeCC = processParam.Value<float>("ExposureTime"); //曝光
  1218. float GainCC = processParam.Value<float>("Gain"); //增益
  1219. float ResultingFrameRateCC = processParam.Value<float>("ResultingFrameRate"); //帧率
  1220. AddTextEvent($"{stepIndex + 1}-{processName}", $"相机开始采集照片...");
  1221. devContainer.devScannerCC.setParam(ExposureTimeCC, GainCC, ResultingFrameRateCC);
  1222. AddTextEvent($"{stepIndex + 1}-{processName}", $"相机参数设置完成。");
  1223. AutoResetEvent endEventCC = new AutoResetEvent(false);
  1224. //devContainer.devScannerCC.ScanEvent = (num, bmp2) =>
  1225. //{
  1226. // AddTextEvent($"{stepIndex + 1}-{processName}", $"相机采集照片完成.");
  1227. // scannerCBmpQueue.Enqueue(bmp2,
  1228. // devContainer.devAxis.getActualPos_mm(0),
  1229. // devContainer.devAxis.getActualPos_mm(1))
  1230. // endEventCC.Set();//线程返回
  1231. //};
  1232. devContainer.devScannerCC.ScanEventPath += new System.Action<int, string>((num, path2) =>
  1233. {
  1234. AddTextEvent($"{stepIndex + 1}-{processName}", $"相机采集照片完成.");
  1235. scannerCBmpQueue.Enqueue(new scannerCBmpLoc(path2,
  1236. devContainer.devAxis.getActualPos_mm(0),
  1237. devContainer.devAxis.getActualPos_mm(1)));//Dequeue
  1238. AddTextEvent($"{stepIndex + 1}-{processName}", $"图像队列数量: {scannerCBmpQueue.Count}");
  1239. endEventCC.Set();//线程返回
  1240. });
  1241. if (!devContainer.devScannerCC.scan(1))//软触发拍照
  1242. {
  1243. devContainer.devScannerCC.ScanEventPath = null;
  1244. AddTextEvent($"{stepIndex + 1}-{processName}", $"相机采集照片失败!", WarningEnum.Low);
  1245. warning(WarningEnum.Low);//终止
  1246. return stepIndex;
  1247. }
  1248. if (!endEventCC.WaitOne(5000))
  1249. {
  1250. devContainer.devScannerCC.ScanEventPath = null;
  1251. AddTextEvent($"{stepIndex + 1}-{processName}", $"相机采集照片超时!", WarningEnum.Low);
  1252. warning(WarningEnum.Low);//终止
  1253. return stepIndex;
  1254. }
  1255. devContainer.devScannerCC.ScanEventPath = null;
  1256. #endregion
  1257. break;
  1258. case "Size":
  1259. #region
  1260. limitThresholdVal = processParam.Value<double>("LimitThresholdVal");
  1261. lowerThresholdVal = processParam.Value<double>("LowerThresholdVal");
  1262. int sizeIndex = processParam.Value<int>("Index");
  1263. double xPos = 0;
  1264. double yPos = 0;
  1265. if (scannerCBmpQueue.Count < 1)
  1266. {
  1267. AddTextEvent($"{stepIndex + 1}-{processName}", $"尺寸检测异常,无源图像!!", WarningEnum.Low);
  1268. warning(WarningEnum.Low);//暂停
  1269. return stepIndex;
  1270. }
  1271. var bmpCBmpQueue = scannerCBmpQueue.Dequeue();
  1272. AddTextEvent($"{stepIndex + 1}-{processName}", $"开始尺寸检测,index:{sizeIndex},图像队列数量: {scannerCBmpQueue.Count}...");
  1273. //需要偏移校正,index=0时不能异步
  1274. endEvent = new AutoResetEvent(false);
  1275. sizeBmpNum++;
  1276. devContainer.libSize.add(new SizeTask()
  1277. {
  1278. index = sizeIndex,
  1279. stepIndex = stepIndex,//仅供回调时用
  1280. engineName = processParam.Value<string>("EngineName"),
  1281. bmp = bmpCBmpQueue.BMP,//bmp/file_path二选一,优先bmp
  1282. file_path = bmpCBmpQueue.Path,
  1283. posX = bmpCBmpQueue.PosX,
  1284. posY = bmpCBmpQueue.PosY,
  1285. MarkPointList= convert(currProductMarkList),
  1286. finishEvent = (res) =>
  1287. {
  1288. if(res.isSucceed)
  1289. {
  1290. AddTextEvent($"{stepIndex + 1}-{processName}", $"尺寸检测完成,index:{res.index}。");
  1291. }
  1292. else
  1293. {
  1294. //setDgvContentCol(liStatocStepIndex, $"失败:{res.resultInfo}");
  1295. AddTextEvent($"{res.stepIndex + 1}-{processName}", $"尺寸检测失败index:{res.index}:{res.resultInfo}");
  1296. //warning(WarningEnum.Low);//暂停 这里不能暂停,stepIndex和scannerBmpQueue队列也不对了
  1297. }
  1298. sizeBmpNumResult++;
  1299. string sizeSavePath = Config.SizeBmp_Path + "\\" + DateTime.Now.ToString("yyyyMMdd") + "\\";
  1300. if (!Directory.Exists(sizeSavePath))
  1301. Directory.CreateDirectory(sizeSavePath);
  1302. sizeSavePath += $"SN{this.SN}_I{res.index}_X{res.posX}_Y{res.posY}.bmp";
  1303. if (res.bmp != null)
  1304. {
  1305. res.bmp.Save(sizeSavePath,ImageFormat.Bmp);
  1306. res.bmp.Dispose();
  1307. res.bmp = null;
  1308. }
  1309. else
  1310. {
  1311. //File.Copy(res.file_path, defectFileName + ".bmp", true);
  1312. API.CopyFile(res.file_path, sizeSavePath, false);//更快
  1313. File.Delete(res.file_path);
  1314. }
  1315. }
  1316. });
  1317. #endregion
  1318. break;
  1319. case "For":
  1320. #region
  1321. long UniqueId = processParam.Value<long>("UniqueId");
  1322. int GotoStepIndex = processParam.Value<int>("GotoStepIndex");//1-n
  1323. int LimitNum = processParam.Value<int>("LimitNum");//1-n
  1324. bool Reset = processParam.Value<bool>("Reset");
  1325. if (GotoStepIndex - 1 == stepIndex)
  1326. {
  1327. AddTextEvent($"{stepIndex + 1}-{processName}", $"For死循环!!!");
  1328. warning(WarningEnum.High);
  1329. return stepIndex;
  1330. }
  1331. if (!devContainer.libFor.dicData.ContainsKey(UniqueId))
  1332. devContainer.libFor.dicData.Add(UniqueId, 0);
  1333. //
  1334. int Num = devContainer.libFor.dicData[UniqueId];
  1335. Num++;
  1336. if (Num <= LimitNum)
  1337. {
  1338. if (Num == LimitNum)
  1339. {
  1340. //setDgvContentCol(liStatocStepIndex, $"第[{Num}/{LimitNum}]次,循环完成");
  1341. AddTextEvent($"{stepIndex + 1}-{processName}", $"第[{Num}/{LimitNum}]次,循环完成。");
  1342. }
  1343. else
  1344. {
  1345. //setDgvContentCol(liStatocStepIndex, $"第[{Num}/{LimitNum}]次");
  1346. AddTextEvent($"{stepIndex + 1}-{processName}", $"第[{Num}/{LimitNum}]次跳转到步骤[{GotoStepIndex}]...");
  1347. stepIndex = GotoStepIndex - 2;
  1348. }
  1349. devContainer.libFor.dicData[UniqueId] = Num;
  1350. }
  1351. else
  1352. {
  1353. //setDgvContentCol(liStatocStepIndex, $"已失效不执行");
  1354. AddTextEvent($"{stepIndex + 1}-{processName}", $"本循环已失效不执行!");
  1355. }
  1356. //达到limit重置0
  1357. if (devContainer.libFor.dicData[UniqueId] >= LimitNum && Reset)
  1358. {
  1359. devContainer.libFor.dicData[UniqueId] = 0;
  1360. //setDgvContentCol(liStatocStepIndex, $"第[0/{LimitNum}]次");
  1361. AddTextEvent($"{stepIndex + 1}-{processName}", $"计数器已重置。");
  1362. }
  1363. #endregion
  1364. break;
  1365. case "If":
  1366. #region
  1367. long UniqueId_if = processParam.Value<long>("UniqueId");
  1368. int GotoStepIndex_if = processParam.Value<int>("GotoStepIndex");//1-n
  1369. int LimitNum_if = processParam.Value<int>("LimitNum");//1-n
  1370. bool Reset_if = processParam.Value<bool>("Reset");
  1371. if (GotoStepIndex_if - 1 == stepIndex)
  1372. {
  1373. AddTextEvent($"{stepIndex + 1}-{processName}", $"If死循环,不可自我跳转!!!");
  1374. warning(WarningEnum.High);
  1375. return stepIndex;
  1376. }
  1377. //
  1378. if (!devContainer.libIF.dicData.ContainsKey(UniqueId_if))
  1379. devContainer.libIF.dicData.Add(UniqueId_if, 0);
  1380. //
  1381. int Num_if = devContainer.libIF.dicData[UniqueId_if];
  1382. Num_if++;
  1383. if (Num_if <= LimitNum_if)
  1384. {
  1385. if (Num_if == LimitNum_if)
  1386. {
  1387. //setDgvContentCol(liStatocStepIndex, $"第[{Num_if}/{LimitNum_if}]次,跳转至[{GotoStepIndex_if}]");
  1388. AddTextEvent($"{stepIndex + 1}-{processName}", $"计数器[{Num_if}/{LimitNum_if}],跳转至步骤[{GotoStepIndex_if}]...");
  1389. stepIndex = GotoStepIndex_if - 2;
  1390. }
  1391. else
  1392. {
  1393. //setDgvContentCol(liStatocStepIndex, $"第[{Num_if}/{LimitNum_if}]次,不跳转");
  1394. AddTextEvent($"{stepIndex + 1}-{processName}", $"计数器[{Num_if}/{LimitNum_if}],不跳转。");
  1395. }
  1396. //
  1397. devContainer.libIF.dicData[UniqueId_if] = Num_if;
  1398. }
  1399. else
  1400. {
  1401. //setDgvContentCol(liStatocStepIndex, $"已失效不执行");
  1402. AddTextEvent($"{stepIndex + 1}-{processName}", $"本IF已失效不执行。");
  1403. }
  1404. //达到limit重置0
  1405. if (devContainer.libIF.dicData[UniqueId_if] >= LimitNum_if && Reset_if)
  1406. {
  1407. devContainer.libIF.dicData[UniqueId_if] = 0;
  1408. //setDgvContentCol(liStatocStepIndex, $"第[0/{LimitNum_if}]次");
  1409. AddTextEvent($"{stepIndex + 1}-{processName}", $"计数器已重置。");
  1410. }
  1411. #endregion
  1412. break;
  1413. default:
  1414. AddTextEvent($"{stepIndex + 1}-{processName}", $"未知工序:{processInfo.ProcessCode}");
  1415. warning(WarningEnum.High);
  1416. return stepIndex;
  1417. }
  1418. if (sleepLater > 0) Thread.Sleep((int)sleepLater);
  1419. }
  1420. //============结束,判断是否自动下料
  1421. if (stepIndex == processList.Count - 1)
  1422. {
  1423. setButtonEnabled(tsbtnPause, false);//后面手动模式暂停无意义
  1424. //等待Mark图处理完成
  1425. while (sizeBmpNum != sizeBmpNumResult)
  1426. Thread.Sleep(100);
  1427. //
  1428. this.Invoke(new System.Action(() =>
  1429. {
  1430. this.chkLaser.Checked = true;
  1431. this.gpbXYAxis.Enabled = gpbZAxis.Enabled = true;
  1432. }));
  1433. AddTextEvent("完成", $"Mark点计算工序结束,开始转换主机台缺陷坐标...");
  1434. convert2LocXY();
  1435. AddTextEvent("完成", $"开始进行人工修复...");
  1436. currentPT = CurrentPTEnum.MakeTag;
  1437. currentState = CurrentStateEnum.打标中;
  1438. setButtonEnabled(tsbtnGoDownPT, true);
  1439. setButtonEnabled(tsbtnReset, true);
  1440. //==
  1441. currProcessIndex = -1;
  1442. return -1;
  1443. }
  1444. else //继续
  1445. {
  1446. return ++stepIndex;
  1447. //return nextProcess(model, ++stepIndex);
  1448. }
  1449. }
  1450. catch (Exception ex)
  1451. {
  1452. if (devContainer.devAxis.isError())
  1453. {
  1454. AddTextEvent("工序", $"[{stepIndex}] Err:" + ex.Message);
  1455. warning(WarningEnum.High);
  1456. }
  1457. else
  1458. {
  1459. AddTextEvent("工序", $"[{stepIndex}] Err:" + ex.Message);
  1460. warning(WarningEnum.Low);
  1461. }
  1462. return -2;
  1463. }
  1464. }
  1465. #endregion
  1466. #region Fun
  1467. /// <summary>
  1468. /// 全局中断
  1469. /// </summary>
  1470. private void globalBreakEvent(int portIndex, byte data)
  1471. {
  1472. AddTextEvent("中断命令", $"{portIndex}-HEX:{Convert.ToString(data, 16)}");
  1473. if (compareIOInput(CMDName.启动按钮) && this.tsbtnStart.Enabled)
  1474. startCommand();
  1475. else if (compareIOInput(CMDName.暂停按钮) && this.tsbtnPause.Enabled)
  1476. warning(WarningEnum.Low, false);
  1477. else if (compareIOInput(CMDName.完成下料) && this.tsbtnGoDownPT.Enabled)
  1478. gotoDownPT();
  1479. else if (compareIOInput(CMDName.下光源按钮))
  1480. openLowerLight();
  1481. else if (compareIOInput(CMDName.上一张图) && currentState == CurrentStateEnum.打标中 && currDefectIndex > 0)
  1482. gotoPrePic();
  1483. else if (compareIOInput(CMDName.下一张图) && currentState == CurrentStateEnum.打标中 && currDefectIndex < defectList.Count - 1)
  1484. gotoNextPic();
  1485. else if (compareIOInput(CMDName.上一缺陷) && currentState == CurrentStateEnum.打标中 && currDefectIndex > 0)
  1486. gotoDefctListIndex(--currDefectIndex, currDefectIndex + 1);
  1487. else if (compareIOInput(CMDName.下一缺陷) && currentState == CurrentStateEnum.打标中 && currDefectIndex < defectList.Count - 1)
  1488. gotoDefctListIndex(++currDefectIndex, currDefectIndex - 1);
  1489. else if (compareIOInput(CMDName.复位按钮) && this.tsbtnReset.Enabled)
  1490. resetCommand();
  1491. //
  1492. if (devContainer.state && warningLevel == WarningEnum.Normal
  1493. && currentState == CurrentStateEnum.打标中 && currentPT == CurrentPTEnum.MakeTag)
  1494. {
  1495. int axisIndex = 0;
  1496. bool isJog_axis = (AxisState)devContainer.devAxis.AxState[axisIndex] == AxisState.STA_AX_EXT_JOG;
  1497. if(!handleJog(axisIndex, CMDName.手柄左移,1) && !handleJog(axisIndex, CMDName.手柄右移,0))
  1498. {
  1499. if (isJog_axis)
  1500. {
  1501. AddTextEvent("中断命令", $"轴{axisIndex}关闭JOG模式!");
  1502. devContainer.devAxis.closeJogMode(axisIndex);//关闭jog时自动停止
  1503. }
  1504. }
  1505. axisIndex = 1;
  1506. isJog_axis = (AxisState)devContainer.devAxis.AxState[axisIndex] == AxisState.STA_AX_EXT_JOG;
  1507. if (!handleJog(axisIndex, CMDName.手柄前移,0) && !handleJog(axisIndex, CMDName.手柄后移,1))
  1508. {
  1509. if (isJog_axis)
  1510. {
  1511. AddTextEvent("中断命令", $"轴{axisIndex}关闭JOG模式!");
  1512. devContainer.devAxis.closeJogMode(axisIndex);//关闭jog时自动停止
  1513. }
  1514. }
  1515. }
  1516. }
  1517. private bool compareIOInput(CMDName key)
  1518. {
  1519. JObject joJson = Config.CMDProcess[key];
  1520. IODirectionEnum direction = (IODirectionEnum)joJson.Value<int>("Direction");
  1521. if (direction == IODirectionEnum.输入 || direction == IODirectionEnum.输入输出)
  1522. {
  1523. return Util.compareIOInput(
  1524. joJson.Value<JArray>("IN_OP_SHOW").ToObject<List<string>>().ToArray(),
  1525. devContainer.devIOCard.DIData);
  1526. }
  1527. return false;
  1528. }
  1529. private bool handleJog(int axisIndex,CMDName cmd,ushort dir)
  1530. {
  1531. if (compareIOInput(cmd) && currentState == CurrentStateEnum.打标中)
  1532. {
  1533. AddTextEvent("中断命令", $"{cmd.ToString()}:开");
  1534. devContainer.devAxis.openJogMode(axisIndex);
  1535. devContainer.devAxis.setAxisVelParam((double)Config.Axis_JogVelLow[axisIndex], (double)Config.Axis_JogVelLow[axisIndex],
  1536. (double)Config.Axis_JogVelLow[axisIndex], (double)Config.Axis_JogVelLow[axisIndex], axisIndex, true);
  1537. devContainer.devAxis.jog(axisIndex, dir);//jog move
  1538. return true;
  1539. }
  1540. return false;
  1541. }
  1542. /// <summary>
  1543. /// 报警,只响应low,high
  1544. /// </summary>
  1545. private void warning(WarningEnum level, bool buzzer = true)
  1546. {
  1547. if (level == WarningEnum.Normal)
  1548. return;
  1549. lock (myLock)
  1550. warningLevel = level;
  1551. if (level == WarningEnum.Low)//暂停
  1552. {
  1553. currentState = CurrentStateEnum.暂停;
  1554. pauseCommand(buzzer);
  1555. }
  1556. else if (level == WarningEnum.High)//急停
  1557. {
  1558. currentState = CurrentStateEnum.急停;
  1559. devContainer.devAxis.stopNow();
  1560. stopNowCommand();
  1561. }
  1562. //启用报警消除按钮
  1563. setButtonEnabled(tsbtnWarning, true);
  1564. }
  1565. private void resetUIValue()
  1566. {
  1567. currProcessIndex = -1;
  1568. currProductModel = null;
  1569. currProductMarkList = null;
  1570. scannerCBmpQueue.Clear();
  1571. defectBmpsDir.Clear();
  1572. this.Invoke(new System.Action(() =>
  1573. {
  1574. cbxSN.Enabled = false;
  1575. cbxSN.Text = txtProductCode.Text = txtProductName.Text = txtBatchId.Text =
  1576. txtBatchId.Text = txtCreateTime.Text = "";
  1577. this.gpbDefectList.Text = $"缺陷明细";
  1578. this.dgvProcess.DataSource = null;
  1579. this.lstLog.Items.Clear();
  1580. this.pictureBox1.Image = null;
  1581. pictureBox1.Refresh();
  1582. }));
  1583. }
  1584. private void delDirFiles(string dirPath)
  1585. {
  1586. try
  1587. {
  1588. var files = Directory.EnumerateFiles(dirPath, "*.bmp", SearchOption.TopDirectoryOnly);
  1589. foreach (string file in files)
  1590. API.DeleteFile(file);
  1591. }
  1592. catch (Exception ex)
  1593. {
  1594. }
  1595. }
  1596. public delegate void AddTextDelegate(string tag, string msg, WarningEnum level);
  1597. /// <summary>
  1598. /// 异步输出日志
  1599. /// </summary>
  1600. /// <param name="tag">模板标识</param>
  1601. /// <param name="msg">内容</param>
  1602. /// <param name="type"></param>
  1603. private void AddTextEvent(string tag, string msg, WarningEnum level = WarningEnum.Normal)
  1604. {
  1605. try
  1606. {
  1607. if (InvokeRequired)
  1608. {
  1609. Invoke(new AddTextDelegate(AddTextEvent), new object[]
  1610. {
  1611. tag,
  1612. msg,
  1613. level
  1614. });
  1615. }
  1616. else
  1617. {
  1618. if (tag != null && tag != "")
  1619. tag = $" - [{tag}]";
  1620. var now = DateTime.Now;
  1621. msg = now.ToString("HH:mm:ss fff") + tag + " - " + msg;
  1622. //cont = MyHelper.subString(cont, 300);
  1623. //写日志,warn和error日志直接写
  1624. writeLog(now, level, msg);
  1625. //
  1626. //if (type > 0)
  1627. // cont = $"<color=\"{(type == 1 ? "Yellow" : "Red")}\">{cont}</color>";
  1628. msg = (level == WarningEnum.Normal ? "B" : level == WarningEnum.Low ? "Y" : "R") + msg;
  1629. this.Invoke(new System.Action(() =>
  1630. {
  1631. if (this.lstLog.Items.Count > 1000)
  1632. this.lstLog.Items.Clear();
  1633. lstLog.Items.Insert(0, msg);
  1634. }));
  1635. //日志滚动
  1636. //lstLog.SelectedIndex = lstLog.Items.Count - 1;
  1637. }
  1638. }
  1639. catch (Exception ex)
  1640. {
  1641. //MessageBox.Show("AddTextEvent ex=(" + ex.Message + ")", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, 0);
  1642. }
  1643. }
  1644. private void lstLog_DrawItem(object sender, DrawItemEventArgs e)
  1645. {
  1646. e.DrawBackground();
  1647. if (e.Index < 0) return;
  1648. string str = lstLog.Items[e.Index].ToString();
  1649. e.Graphics.DrawString(str.Substring(1), e.Font,
  1650. new SolidBrush(str[0] == 'R' ? Color.Red : (str[0] == 'Y' ? Color.Orange : Color.Black)),
  1651. e.Bounds);
  1652. }
  1653. private void writeLog(DateTime now, WarningEnum level, string text)
  1654. {
  1655. string directory = Config.LogPath + "\\" + DateTime.Now.ToString("yyyyMM") + "\\";
  1656. //if (type == 0) directory = Application.StartupPath + "\\Log\\Info\\";
  1657. //else if (type == 1) directory = Application.StartupPath + "\\Log\\Warn\\";
  1658. //else directory = Application.StartupPath + "\\Log\\Error\\";
  1659. if (!System.IO.Directory.Exists(directory))
  1660. System.IO.Directory.CreateDirectory(directory);
  1661. File.AppendAllText(directory + now.ToString("yyyyMMdd") + ".log", text + "\r\n");
  1662. }
  1663. #endregion
  1664. private void tsbtnOpenDev_Click(object sender, EventArgs e)
  1665. {
  1666. Config.LoadAllConfig();
  1667. if(string.IsNullOrWhiteSpace(Config.DBConStr)|| string.IsNullOrWhiteSpace(Config.ServerIP))
  1668. {
  1669. AddTextEvent("设备启动", "启动失败,请先设置数据库和主机台通讯地址!",WarningEnum.High);
  1670. return;
  1671. }
  1672. //设置程序最小/大线程池
  1673. // Get the current settings.
  1674. int minWorker, minIOC;
  1675. ThreadPool.GetMinThreads(out minWorker, out minIOC);
  1676. ThreadPool.SetMinThreads(25, minIOC);
  1677. //ThreadPool.SetMaxThreads(256, 256);
  1678. this.tsbtnOpenDev.Enabled = false;
  1679. scannerCBmpQueue.Clear();
  1680. //scannerCBmpIndex = 0;
  1681. this.resetUIValue();
  1682. currentState = CurrentStateEnum.等待复位;
  1683. warningLevel = WarningEnum.Normal;
  1684. currentPT = CurrentPTEnum.InitPT;
  1685. this.tsbtnWarning.Enabled = this.tsbtnGoDownPT.Enabled = this.tsbtnStart.Enabled
  1686. = this.tsbtnStopNow.Enabled = this.tsbtnPause.Enabled = this.tsbtnReset.Enabled
  1687. = this.gpbXYAxis.Enabled = gpbZAxis.Enabled = false;
  1688. //后台线程回调事件
  1689. devContainer.StateChange = (state, msg) =>
  1690. {
  1691. if (state)
  1692. {
  1693. //全局中断
  1694. devContainer.devIOCard.INEvent = globalBreakEvent;
  1695. devContainer.OutDebugEvent = (tag, debugInfo) =>
  1696. {
  1697. AddTextEvent(tag, debugInfo);
  1698. };
  1699. //
  1700. AddTextEvent("设备启动", "请先进行复位操作!");
  1701. this.Invoke(new System.Action(() =>
  1702. {
  1703. this.tsbtnReset.Enabled = true;
  1704. tsbtnWarning.Enabled = this.tsbtnStart.Enabled = this.tsbtnGoDownPT.Enabled
  1705. = this.tsbtnPause.Enabled = this.tsbtnStopNow.Enabled = false;
  1706. this.chkLaser.Enabled = true;
  1707. this.tsbtnOpenDev.Enabled = true;
  1708. this.tsbtnOpenDev.Visible = false;
  1709. this.tsbtnCloseDev.Visible = true;
  1710. }));
  1711. timer.Elapsed += Timer_Elapsed;
  1712. timer.Interval = 500;
  1713. timer.Start();
  1714. }
  1715. else
  1716. {
  1717. AddTextEvent("设备启动", $"启动失败,{msg}", WarningEnum.High);
  1718. this.Invoke(new System.Action(() =>
  1719. {
  1720. this.chkLaser.Enabled = false;
  1721. this.tsbtnOpenDev.Enabled = true;
  1722. this.tsbtnOpenDev.Visible = true;
  1723. this.tsbtnCloseDev.Visible = false;
  1724. }));
  1725. }
  1726. };
  1727. devContainer.WarningEvent = (level, msg) =>
  1728. {
  1729. AddTextEvent("设备事件", msg, level);
  1730. if (level == WarningEnum.High)
  1731. warning(level, true);
  1732. };
  1733. devContainer.start(IntPtr.Zero, IntPtr.Zero);
  1734. }
  1735. private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
  1736. {
  1737. this.Invoke(new System.Action(() =>
  1738. {
  1739. this.tsAxisState.Text = $"[命令位:{devContainer.devAxis.CmdPos[0]} 反馈位:{devContainer.devAxis.ActualPos[0]} ({((AxisState)devContainer.devAxis.AxState[0]).ToString()})] | " +
  1740. $"[命令位:{devContainer.devAxis.CmdPos[1]} 反馈位:{devContainer.devAxis.ActualPos[1]} ({((AxisState)devContainer.devAxis.AxState[1]).ToString()})] | " +
  1741. $"[命令位:{devContainer.devAxis.CmdPos[2]} 反馈位:{devContainer.devAxis.ActualPos[2]} ({((AxisState)devContainer.devAxis.AxState[2]).ToString()})] | " +
  1742. $"[命令位:{devContainer.devAxis.CmdPos[3]} 反馈位:{devContainer.devAxis.ActualPos[3]} ({((AxisState)devContainer.devAxis.AxState[3]).ToString()})] | ";
  1743. }));
  1744. }
  1745. private void tsbtnCloseDev_Click(object sender, EventArgs e)
  1746. {
  1747. AddTextEvent("设备停止", $"设备停止...");
  1748. this.tsbtnOpenDev.Visible = true;
  1749. this.tsbtnCloseDev.Visible = false;
  1750. this.chkLaser.Enabled = false;
  1751. this.tsbtnReset.Enabled = tsbtnWarning.Enabled = this.tsbtnStart.Enabled = this.tsbtnGoDownPT.Enabled
  1752. = this.tsbtnPause.Enabled = this.tsbtnStopNow.Enabled
  1753. = this.gpbXYAxis.Enabled = this.gpbZAxis.Enabled = false;
  1754. if (devContainer.state)
  1755. {
  1756. devContainer.devIOCard.reset();
  1757. devContainer.io_output(CMDName.IO默认输出);
  1758. }
  1759. timer.Stop();
  1760. devContainer.stop();
  1761. }
  1762. private void dgvProcess_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
  1763. {
  1764. if (e.RowIndex < 0 || !devContainer.state || currentState != CurrentStateEnum.打标中)
  1765. return;
  1766. int preIndex = currDefectIndex;
  1767. currDefectIndex = e.RowIndex;
  1768. gotoDefctListIndex(currDefectIndex, preIndex);
  1769. }
  1770. private void 流程管理ToolStripMenuItem_Click(object sender, EventArgs e)
  1771. {
  1772. if (devContainer.state)
  1773. {
  1774. MessageBox.Show("请先停止设备,再进行流程修改!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  1775. return;
  1776. }
  1777. FrmStepList frm = new FrmStepList();
  1778. frm.ShowDialog();
  1779. }
  1780. private void 产品管理ToolStripMenuItem_Click(object sender, EventArgs e)
  1781. {
  1782. //if (devContainer.state)
  1783. //{
  1784. // MessageBox.Show("请先停止设备,再进行产品修改!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  1785. // return;
  1786. //}
  1787. FrmProductList frm = new FrmProductList();
  1788. frm.ShowDialog();
  1789. }
  1790. private void loadOrderSNList()
  1791. {
  1792. try
  1793. {
  1794. //ConditionalType: 0-等于 3-大于等于 5-小于等于 6-IN "CSharpTypeName":"int"
  1795. JArray domainList =new JArray();
  1796. domainList.Add(new JObject()
  1797. {
  1798. {"FieldName","State" },
  1799. {"FieldValue",0 },//0-初始; 5-已检测
  1800. {"ConditionalType",0 },
  1801. });
  1802. domainList.Add(new JObject()
  1803. {
  1804. {"FieldName","DefectCount" },
  1805. {"FieldValue",1 },
  1806. {"ConditionalType",3 },
  1807. });
  1808. domainList.Add(new JObject()
  1809. {
  1810. {"FieldName","CreateTime" },
  1811. {"FieldValue",DateTime.Now.AddDays(-1) },
  1812. {"ConditionalType",3 },
  1813. });
  1814. var list = svcOrder.GetList("Order", "SN", domainList.ToString(), "SN DESC");
  1815. List<string> snList = new List<string>();
  1816. foreach(var item in list)
  1817. snList.Add(item.ToList().Select(m => m.Value.ToString()).ToArray()[0]);
  1818. this.Invoke(new System.Action(() =>
  1819. {
  1820. this.cbxSN.Text = "";
  1821. this.cbxSN.Items.Clear();
  1822. this.cbxSN.Items.AddRange(snList.ToArray());
  1823. }));
  1824. }
  1825. catch (Exception ex)
  1826. {
  1827. AddTextEvent("启动", "加载已检测网版编码失败:" + ex.Message, WarningEnum.Low);
  1828. }
  1829. }
  1830. private void splitContainer1_SizeChanged(object sender, EventArgs e)
  1831. {
  1832. this.gpbProductInfo.Width = this.gpbDefectList.Width = splitContainer1.Panel2.Width-10;
  1833. this.gpbProductInfo.Top = this.splitContainer1.ClientSize.Height- this.gpbProductInfo.Height;
  1834. this.gpbDefectList.Height = this.gpbProductInfo.Top-10;
  1835. this.cbxSN.Width= this.txtProductCode.Width = this.txtProductName.Width
  1836. = this.txtBatchId.Width = this.txtCreateTime.Width = this.gpbProductInfo.Width- this.cbxSN.Left-5;
  1837. //this.dgvProcess.Width = gpbDefectList.Width - 10;
  1838. //this.dgvProcess.Height = this.splitContainer1.ClientSize.Height - this.gpbProductInfo.Height;
  1839. //
  1840. }
  1841. private void splitContainer2_SizeChanged(object sender, EventArgs e)
  1842. {
  1843. this.tsbtnPause.Left = this.tsbtnGoDownPT.Left = this.splitContainer1.SplitterDistance- this.tsbtnPause.Width - 10;
  1844. this.gpbZAxis.Left = this.tsbtnPause.Left - this.gpbZAxis.Width-10;
  1845. this.gpbXYAxis.Left = this.gpbZAxis.Left - this.gpbXYAxis.Width - 10;
  1846. this.gpbLog.Width = this.gpbXYAxis.Left - 10;
  1847. this.splitContainer2.SplitterDistance = this.ClientRectangle.Height - gpbLog.Height - 10;
  1848. }
  1849. private void tsbtnReset_Click(object sender, EventArgs e)
  1850. {
  1851. Task.Run(() => this.resetCommand());
  1852. }
  1853. private void tsbtnStart_Click(object sender, EventArgs e)
  1854. {
  1855. Task.Run(() => this.startCommand());
  1856. }
  1857. private void tsbtnPause_Click(object sender, EventArgs e)
  1858. {
  1859. warning(WarningEnum.Low, false);
  1860. }
  1861. private void tsbtnGoDownPT_Click(object sender, EventArgs e)
  1862. {
  1863. Task.Run(() => this.gotoDownPT());
  1864. }
  1865. private void tsbtnWarning_Click(object sender, EventArgs e)
  1866. {
  1867. //if (warningLevel == WarningEnum.Normal)
  1868. //{
  1869. // tsbtnWarning.Enabled = false;
  1870. // return;
  1871. //}
  1872. //重置AXIS状态
  1873. devContainer.devAxis.resetAxisState();
  1874. if (!devContainer.devAxis.isReady())
  1875. {
  1876. AddTextEvent("解除报警", "轴状态未恢复,解除报警失败!", warningLevel);
  1877. return;
  1878. }
  1879. if (devContainer.devAxis.isError())
  1880. {
  1881. AddTextEvent("解除报警", "轴IO状态异常,解除报警失败!", warningLevel);
  1882. return;
  1883. }
  1884. //if (!this.disableDoorSensor && compareIOInput(CMDName.门磁告警输入))
  1885. //{
  1886. // AddTextEvent("解除报警", "门磁告警未清除 ,解除报警失败!", warningLevel);
  1887. // return;
  1888. //}
  1889. //if (!this.disableDoorSensor && compareIOInput(CMDName.喷墨告警输入))
  1890. //{
  1891. // AddTextEvent("解除报警", "喷墨告警输入未清除 ,解除报警失败!", warningLevel);
  1892. // return;
  1893. //}
  1894. ////关闭蜂鸣器
  1895. //devContainer.io_output(CMDName.蜂鸣器输出, false, true, 0);
  1896. //devContainer.io_output(CMDName.红灯输出, false, true, 0);
  1897. //devContainer.io_output(CMDName.复位按钮, false, true, 0);
  1898. if (warningLevel == WarningEnum.High)
  1899. {
  1900. AddTextEvent("解除报警", "急停告警已解除,但必需进行复位操作!", warningLevel);
  1901. currentState = CurrentStateEnum.等待复位;
  1902. this.tsbtnReset.Enabled = true;
  1903. tsbtnWarning.Enabled = this.tsbtnStart.Enabled = this.tsbtnGoDownPT.Enabled
  1904. = this.tsbtnPause.Enabled = this.tsbtnStopNow.Enabled = false;
  1905. }
  1906. else
  1907. {
  1908. //devContainer.io_output(CMDName.黄灯输出);
  1909. AddTextEvent("解除报警", "告警已解除,请继续选择下一步操作!", warningLevel);
  1910. if (currentPT == CurrentPTEnum.MakeTag)
  1911. currentState = CurrentStateEnum.打标中;
  1912. else
  1913. currentState = CurrentStateEnum.等待启动;
  1914. tsbtnWarning.Enabled = false;
  1915. this.tsbtnStart.Enabled = this.tsbtnGoDownPT.Enabled = true;
  1916. this.tsbtnReset.Enabled = this.tsbtnPause.Enabled = this.tsbtnStopNow.Enabled = true;
  1917. }
  1918. warningLevel = WarningEnum.Normal;
  1919. }
  1920. private void 测试ToolStripMenuItem_Click(object sender, EventArgs e)
  1921. {
  1922. //devContainer.start(IntPtr.Zero, IntPtr.Zero);
  1923. //devContainer.state = true;
  1924. //currentState = CurrentStateEnum.等待扫码;
  1925. //cbxSN.Enabled = true;
  1926. //runStep();
  1927. //Bitmap bmp = (Bitmap)Bitmap.FromFile(Application.StartupPath + "\\test.bmp");
  1928. //AddTextEvent("", $"{this.splitContainer1.Width},{this.pnlPic.Width},bmp:{bmp.Width}");
  1929. //pnlPic.BackColor = Color.Red;
  1930. //reloadPic(bmp);
  1931. //for (int i = 0; i < 100; i++)
  1932. // this.dgvProcess.Rows.Add(i, i, i, i, i, i, i, i, i, i, i);
  1933. //this.dgvProcess.Rows[1].DefaultCellStyle.BackColor = Color.LightGreen;
  1934. //loadOrderSNList();
  1935. }
  1936. private void btnFront_MouseDown(object sender, MouseEventArgs e)
  1937. {
  1938. if (devContainer.state && currentState == CurrentStateEnum.打标中)
  1939. {
  1940. ushort dir;
  1941. int axisIndex;
  1942. PictureBox btn = sender as PictureBox;
  1943. switch (btn.Name)
  1944. {
  1945. case "btnFront":
  1946. dir = 1;
  1947. axisIndex = 1;
  1948. break;
  1949. case "btnBack":
  1950. dir = 0;
  1951. axisIndex = 1;
  1952. break;
  1953. case "btnLeft":
  1954. dir = 1;
  1955. axisIndex = 0;
  1956. break;
  1957. case "btnRight":
  1958. dir = 0;
  1959. axisIndex = 0;
  1960. break;
  1961. case "btnZUp":
  1962. dir = 0;
  1963. axisIndex = 2;
  1964. break;
  1965. case "btnZDown":
  1966. dir = 1;
  1967. axisIndex = 2;
  1968. break;
  1969. default:
  1970. return;
  1971. }
  1972. //
  1973. devContainer.devAxis.openJogMode(axisIndex);
  1974. devContainer.devAxis.setAxisVelParam((double)Config.Axis_JogVelLow[axisIndex], (double)Config.Axis_JogVelLow[axisIndex],
  1975. (double)Config.Axis_JogVelLow[axisIndex], (double)Config.Axis_JogVelLow[axisIndex], axisIndex, true);
  1976. devContainer.devAxis.jog(axisIndex, dir);//jog move
  1977. }
  1978. }
  1979. private void btnFront_MouseUp(object sender, MouseEventArgs e)
  1980. {
  1981. devContainer.devAxis.closeJogMode();
  1982. }
  1983. private void chkLaser_CheckedChanged(object sender, EventArgs e)
  1984. {
  1985. if (!devContainer.state) return;
  1986. if(chkLaser.Checked)
  1987. devContainer.io_output(CMDName.激光灯输出);
  1988. else
  1989. devContainer.io_output(CMDName.激光灯输出, false, true, 0);
  1990. }
  1991. private void tsbtnLog_Click(object sender, EventArgs e)
  1992. {
  1993. if (string.IsNullOrWhiteSpace(Config.LogPath)) return;
  1994. string lsPath = (Config.LogPath + "\\" + DateTime.Now.ToString("yyyyMM") + "\\").Replace("\\\\", "\\");
  1995. if (!Directory.Exists(lsPath))
  1996. Directory.CreateDirectory(lsPath);
  1997. System.Diagnostics.Process.Start("explorer.exe", lsPath);
  1998. }
  1999. private void FrmMain_KeyUp(object sender, KeyEventArgs e)
  2000. {
  2001. //AddTextEvent("KEY",e.KeyCode.ToString());
  2002. switch (e.KeyCode)
  2003. {
  2004. //case Keys.Left://上一张图
  2005. // if (devContainer.state && currentState == CurrentStateEnum.打标中 && currDefectIndex > 0)
  2006. // gotoPrePic();
  2007. // break;
  2008. case Keys.F:// Keys.Right://下一张图
  2009. if (devContainer.state && currentState == CurrentStateEnum.打标中 && currDefectIndex < defectList.Count - 1)
  2010. gotoNextPic();
  2011. break;
  2012. case Keys.K://Keys.Up://上一缺陷
  2013. if (devContainer.state && currentState == CurrentStateEnum.打标中 && currDefectIndex > 0)
  2014. gotoDefctListIndex(--currDefectIndex, currDefectIndex+1);
  2015. break;
  2016. case Keys.P://Keys.Down://下一缺陷
  2017. if (devContainer.state && currentState == CurrentStateEnum.打标中 && currDefectIndex < defectList.Count - 1)
  2018. gotoDefctListIndex(++currDefectIndex, currDefectIndex-1);
  2019. break;
  2020. }
  2021. }
  2022. private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
  2023. {
  2024. }
  2025. private void cbxSN_KeyUp(object sender, KeyEventArgs e)
  2026. {
  2027. if (e.KeyCode == Keys.Enter)
  2028. {
  2029. if (currentState != CurrentStateEnum.等待扫码) return;
  2030. string sn = this.cbxSN.Text.Trim();
  2031. if (string.IsNullOrWhiteSpace(sn))
  2032. return;
  2033. //FrmInput frm = new FrmInput(productCodeList, "请选择产品编码:");
  2034. //if (frm.ShowDialog() != DialogResult.OK && string.IsNullOrWhiteSpace(frm.inputData))
  2035. // return;
  2036. Task.Factory.StartNew(() =>
  2037. {
  2038. devContainer.devCodeScanner.ScanerEvent?.Invoke(sn);
  2039. });
  2040. }
  2041. }
  2042. private void cbxSN_KeyPress(object sender, KeyPressEventArgs e)
  2043. {
  2044. //if (e.KeyChar == (char)Keys.Enter)
  2045. //{
  2046. // if (currentState != CurrentStateEnum.等待扫码) return;
  2047. // string sn = this.cbxSN.Text.Trim();
  2048. // if (string.IsNullOrWhiteSpace(sn))
  2049. // return;
  2050. // //FrmInput frm = new FrmInput(productCodeList, "请选择产品编码:");
  2051. // //if (frm.ShowDialog() != DialogResult.OK && string.IsNullOrWhiteSpace(frm.inputData))
  2052. // // return;
  2053. // Task.Factory.StartNew(() =>
  2054. // {
  2055. // devContainer.devCodeScanner.ScanerEvent?.Invoke(sn);
  2056. // });
  2057. //}
  2058. }
  2059. }
  2060. }