using System; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO.Ports; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using UAS_MES_NEW.DataOperate; using UAS_MES_NEW.Entity; using UAS_MES_NEW.PublicMethod; namespace UAS_MES_NEW.Make { public partial class Make_GetTestData : Form { DataHelper dh; AutoSizeFormClass asc = new AutoSizeFormClass(); LogStringBuilder sql = new LogStringBuilder(); string oErrorMessage = ""; string oMakeCode = ""; string oMsID = ""; public Make_GetTestData() { InitializeComponent(); } private void Make_GetTestData_Load(object sender, EventArgs e) { asc.controllInitializeSize(this); dh = SystemInf.dh; //默认选中两组串口参数(SCPI协议: 9600/8/N/1/None) BaudRate1.SelectedIndex = 4; DataBits1.SelectedIndex = 0; Parity1.SelectedIndex = 0; StopBits1.SelectedIndex = 0; Handshake1.SelectedIndex = 0; BaudRate2.SelectedIndex = 4; DataBits2.SelectedIndex = 0; Parity2.SelectedIndex = 0; StopBits2.SelectedIndex = 0; Handshake2.SelectedIndex = 0; //聚焦SN输入框 sncode.Focus(); OperateResult.AppendText(">>请输入SN\n", Color.Black); //初始化工步计数 StepCount.StepCode = User.CurrentStepCode; StepCount.Source = User.UserSourceCode; StepCount.LineCode = User.UserLineCode; StepCount.Dh = dh; StepCount.Start(); } private void Make_GetTestData_SizeChanged(object sender, EventArgs e) { asc.controlAutoSize(this); } /// /// 根据界面第 portIndex 组串口设置创建并配置SerialPort /// portIndex: 0=串口1, 1=串口2 /// private SerialPort CreateSerialPort(int portIndex, int readTimeout = 3000) { //读取对应组的控件值 string portName; string baudText, dataBitsText, parityText, stopBitsText, handshakeText; if (portIndex == 0) { portName = ComList1.Text; baudText = BaudRate1.Text; dataBitsText = DataBits1.Text; parityText = Parity1.Text; stopBitsText = StopBits1.Text; handshakeText = Handshake1.Text; } else { portName = ComList2.Text; baudText = BaudRate2.Text; dataBitsText = DataBits2.Text; parityText = Parity2.Text; stopBitsText = StopBits2.Text; handshakeText = Handshake2.Text; } int baud = 9600; int.TryParse(baudText, out baud); int dataBits = 8; int.TryParse(dataBitsText, out dataBits); System.IO.Ports.Parity parity = System.IO.Ports.Parity.None; switch (parityText) { case "Odd": parity = System.IO.Ports.Parity.Odd; break; case "Even": parity = System.IO.Ports.Parity.Even; break; case "Mark": parity = System.IO.Ports.Parity.Mark; break; case "Space": parity = System.IO.Ports.Parity.Space; break; } System.IO.Ports.StopBits stopBits = System.IO.Ports.StopBits.One; switch (stopBitsText) { case "1.5": stopBits = System.IO.Ports.StopBits.OnePointFive; break; case "2": stopBits = System.IO.Ports.StopBits.Two; break; } System.IO.Ports.Handshake handshake = System.IO.Ports.Handshake.None; switch (handshakeText) { case "Hardware": handshake = System.IO.Ports.Handshake.RequestToSend; break; case "XOnXOff": handshake = System.IO.Ports.Handshake.XOnXOff; break; case "Both": handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff; break; } SerialPort sp = new SerialPort(); sp.PortName = portName; sp.BaudRate = baud; sp.DataBits = dataBits; sp.Parity = parity; sp.StopBits = stopBits; sp.Handshake = handshake; sp.NewLine = "\r\n"; sp.ReadTimeout = readTimeout; sp.WriteTimeout = 1000; return sp; } /// /// 从指定串口采集数据:打开串口 -> 发送命令(回车结尾) -> 读取返回 /// 每个串口在独立线程中调用,互不干扰。 /// /// 0=串口1, 1=串口2 /// 要发送的命令文本(不带换行) /// 原始返回文本; 失败或无返回返回空字符串 private string CollectFromPort(int portIndex, string command) { string portName = portIndex == 0 ? ComList1.Text : ComList2.Text; if (portName == "") return ""; SerialPort sp = CreateSerialPort(portIndex); string result = ""; try { sp.Open(); //发送命令(WriteLine 自动追加 NewLine = \r\n) sp.WriteLine(command); //等待设备响应 Thread.Sleep(500); //读取返回数据(以回车换行结尾) result = sp.ReadLine().Trim(); sp.Close(); } catch (Exception ex) { if (sp.IsOpen) sp.Close(); //把异常信息带回主线程记录 result = "ERROR:" + ex.Message; } return result; } /// /// 从串口返回文本中提取"逗号之前"的数据(对应HTML中的 extractResistance) /// 仪器返回形如 "100500,0.25,OK" 时只取 "100500" /// private string ExtractResistance(string text) { if (string.IsNullOrEmpty(text)) return ""; string s = text; //只取第一行有效内容 int nl = s.IndexOfAny(new char[] { '\r', '\n' }); if (nl >= 0) s = s.Substring(0, nl); //取第一个半角逗号之前的内容(兼容全角逗号) int idx = s.IndexOf(','); if (idx < 0) idx = s.IndexOf(','); if (idx >= 0) s = s.Substring(0, idx); //清理不可见控制字符与首尾空白 StringBuilder sb = new StringBuilder(); foreach (char c in s) { if (c >= 0x20 && c != 0x7F) sb.Append(c); } return sb.ToString().Trim(); } /// /// 判定两个电阻值是否都严格落在开区间 (lower, upper) 内(对应HTML中的 judgeResult) /// 等于边界值判FAIL /// private bool JudgePass(string v1, string v2, double lower, double upper, out string reason) { reason = ""; double n1, n2; if (!double.TryParse(v1, out n1)) { reason = "4G-1非数值(" + v1 + ")"; return false; } if (!double.TryParse(v2, out n2)) { reason = "4G-2非数值(" + v2 + ")"; return false; } if (n1 <= lower) { reason = "4G-1低于下限(" + v1 + "<=" + lower + ")"; return false; } if (n1 >= upper) { reason = "4G-1高于上限(" + v1 + ">=" + upper + ")"; return false; } if (n2 <= lower) { reason = "4G-2低于下限(" + v2 + "<=" + lower + ")"; return false; } if (n2 >= upper) { reason = "4G-2高于上限(" + v2 + ">=" + upper + ")"; return false; } return true; } private void LoadCollectedNum() { sql.Clear(); sql.Append("select ma_code,nvl(mcd_okqty,0) mcd_okqty,ma_prodcode,pr_detail,"); sql.Append("ma_qty - nvl(mcd_okqty, 0) remain_qty from make left join makecraftdetail on "); sql.Append("mcd_maid=ma_id left join product on pr_code=ma_prodcode where ma_code='" + oMakeCode + "' and mcd_stepcode='" + User.CurrentStepCode + "'"); DataTable dt = (DataTable)dh.ExecuteSql(sql.GetString(), "select"); BaseUtil.SetFormValue(Controls, dt); } private void sncode_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode != Keys.Enter) return; //1) 校验SN非空 if (sncode.Text == "") { OperateResult.AppendText("<<输入不能为空\n", Color.Red); return; } //2) 校验工步属性 if (!LogicHandler.CheckStepAttribute(Tag.ToString(), User.UserSourceCode, out oErrorMessage)) { OperateResult.AppendText(">>" + oErrorMessage + "\n", Color.Red, sncode); return; } //3) 获取工单信息 string oStatus = ""; if (!LogicHandler.GetMakeInfo(sncode.Text, out oMakeCode, out oStatus, out oErrorMessage)) { if (ms_makecode.Text == "") { OperateResult.AppendText(">>" + oErrorMessage + "\n", Color.Red, sncode); return; } } //4) CheckStepSNAndMacode 校验SN与工单 if (LogicHandler.CheckStepSNAndMacode(ms_makecode.Text == "" ? oMakeCode : ms_makecode.Text, User.UserSourceCode, sncode.Text, User.UserCode, out oMakeCode, out oMsID, out oErrorMessage)) { //查询并显示工单产品信息 sql.Clear(); sql.Append("select ms_makecode,ms_prodcode,pr_detail from makeserial left join product on "); sql.Append(" ms_prodcode = pr_code where ms_id = '" + oMsID + "'"); DataTable dt = (DataTable)dh.ExecuteSql(sql.GetString(), "select"); BaseUtil.SetFormValue(this.Controls, dt); LoadCollectedNum(); OperateResult.AppendText(">>" + sncode.Text + " SN校验通过, 开始双串口并发采集\n", Color.Black); //5) 双串口并发采集(对应HTML doScan: 向两个已连接串口同时发送同一条命令) string command = CommandBox.Text.Trim(); if (command == "") { OperateResult.AppendText(">>发送命令不能为空\n", Color.Red, sncode); return; } //检查至少配置了一个串口 if (ComList1.Text == "" && ComList2.Text == "") { OperateResult.AppendText(">>请至少选择一个串口\n", Color.Red, sncode); return; } //并发: 两个串口各自在独立线程中打开、发送、读取(.NET 4.0 用 Task.Factory.StartNew) var t1 = Task.Factory.StartNew(() => CollectFromPort(0, command)); var t2 = Task.Factory.StartNew(() => CollectFromPort(1, command)); Task.WaitAll(t1, t2); string raw1 = t1.Result; string raw2 = t2.Result; //记录原始返回 if (raw1 != "") OperateResult.AppendText(">>[串口1]原始返回:" + raw1 + "\n", Color.Black); else OperateResult.AppendText(">>[串口1]未返回数据(未配置或通讯失败)\n", Color.Red); if (raw2 != "") OperateResult.AppendText(">>[串口2]原始返回:" + raw2 + "\n", Color.Black); else OperateResult.AppendText(">>[串口2]未返回数据(未配置或通讯失败)\n", Color.Red); //6) 提取逗号前的数据(对应HTML extractResistance) string val1 = ExtractResistance(raw1); string val2 = ExtractResistance(raw2); OperateResult.AppendText(">>4G-1提取值:" + (val1 == "" ? "无" : val1) + " 4G-2提取值:" + (val2 == "" ? "无" : val2) + "\n", Color.Black); //7) 插入STEPTESTDETAIL(两路数据分别入库, std_makecode=工单编号) if (val1 != "") { dh.ExecuteSql("insert into STEPTESTDETAIL(std_id,std_sn,std_makecode,std_indate,std_class,std_testtimes,std_actualvalue,std_testresult,std_rescode) values(STEPTESTDETAIL_seq.nextval,'" + sncode.Text + "','" + oMakeCode + "',sysdate,'4G-1','','" + val1 + "','OK','"+User.UserSourceCode+"')", "insert"); } if (val2 != "") { dh.ExecuteSql("insert into STEPTESTDETAIL(std_id,std_sn,std_makecode,std_indate,std_class,std_testtimes,std_actualvalue,std_testresult,std_rescode) values(STEPTESTDETAIL_seq.nextval,'" + sncode.Text + "','" + oMakeCode + "',sysdate,'4G-2','','" + val2 + "','OK','"+User.UserSourceCode+"')", "insert"); } //8) 上下限判定(对应HTML judgeResult: 开区间, 不含边界) double lower = 99000, upper = 101000; double.TryParse(LowerLimit.Text, out lower); double.TryParse(UpperLimit.Text, out upper); string reason; bool pass = JudgePass(val1, val2, lower, upper, out reason); //9) 过站: 测试PASS才执行过站, FAIL不过站 if (pass) { if (LogicHandler.SetStepResult(oMakeCode, User.UserSourceCode, sncode.Text, "电桥测试", "OK", User.UserCode, out oErrorMessage)) { //提示正确返回时传递的信息 if (oErrorMessage.Contains("AFTERSUCCESS")) OperateResult.AppendText(">>" + oErrorMessage + "\n"); //刷新工单计数 LoadCollectedNum(); //记录日志 LogicHandler.DoCommandLog(Tag.ToString(), User.UserCode, oMakeCode, User.UserLineCode, User.UserSourceCode, "电桥测试", "双串口测试通过", sncode.Text, ""); OperateResult.AppendText("<<" + sncode.Text + "测试PASS(4G-1=" + val1 + " 4G-2=" + val2 + ") 过站成功\n", Color.Green, sncode); OperateResult.AppendText(">>请输入SN\n", Color.Black); } else { OperateResult.AppendText(">>过站失败:" + oErrorMessage + "\n", Color.Red, sncode); } } else { //测试不通过: 不执行过站, 只记录日志和提示 LogicHandler.DoCommandLog(Tag.ToString(), User.UserCode, oMakeCode, User.UserLineCode, User.UserSourceCode, "电桥测试", "测试失败:" + reason, sncode.Text, ""); OperateResult.AppendText("<<" + sncode.Text + "测试FAIL " + reason + " 未过站\n", Color.Red, sncode); OperateResult.AppendText(">>请输入SN\n", Color.Black); } //清空SN输入框, 准备下一次扫码 sncode.Text = ""; sncode.Focus(); } else { OperateResult.AppendText(">>" + oErrorMessage + "\n", Color.Red, sncode); } } } }