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) 过站 SetStepResult(判定结果决定过站OK/NG)
string stepResult = pass ? "OK" : "NG";
string stepRemark = pass ? "双串口测试通过" : ("测试失败:" + reason);
if (LogicHandler.SetStepResult(oMakeCode, User.UserSourceCode, sncode.Text, "电桥测试", stepResult, User.UserCode, out oErrorMessage))
{
//提示正确返回时传递的信息
if (oErrorMessage.Contains("AFTERSUCCESS"))
OperateResult.AppendText(">>" + oErrorMessage + "\n");
//刷新工单计数
LoadCollectedNum();
//记录日志
LogicHandler.DoCommandLog(Tag.ToString(), User.UserCode, oMakeCode, User.UserLineCode, User.UserSourceCode, "电桥测试", stepRemark, sncode.Text, "");
if (pass)
OperateResult.AppendText("<<" + sncode.Text + "测试PASS(4G-1=" + val1 + " 4G-2=" + val2 + ") 过站成功\n", Color.Green, sncode);
else
OperateResult.AppendText("<<" + sncode.Text + "测试FAIL " + reason + " 过站记录NG\n", Color.Red, sncode);
OperateResult.AppendText(">>请输入SN\n", Color.Black);
}
else
{
OperateResult.AppendText(">>过站失败:" + oErrorMessage + "\n", Color.Red, sncode);
}
//清空SN输入框, 准备下一次扫码
sncode.Text = "";
sncode.Focus();
}
else
{
OperateResult.AppendText(">>" + oErrorMessage + "\n", Color.Red, sncode);
}
}
}
}