Commit aca05b44 几米阳光

批量上料轴极限信号改为IODI27。

批量上下料功能修改。
1 个父辈 17d8ddf4
此文件类型无法预览
<?xml version="1.0"?>
<doc>
<assembly>
<name>Asa.IOModule.AIOBOX</name>
</assembly>
<members>
<member name="T:Asa.IOModule.AIOBOX">
<summary>
AIOBOX操作类
</summary>
</member>
<member name="T:Asa.IOModule.AIOBOX.DI_Changed">
<summary>
自动读取DI委托
</summary>
<param name="box">AIOBOX</param>
<param name="sta">所有DI状态</param>
</member>
<member name="E:Asa.IOModule.AIOBOX.DI_Changed_Event">
<summary>
自动读取DI事件触发
</summary>
</member>
<member name="T:Asa.IOModule.AIOBOX.DO_Changed">
<summary>
自动读取DO委托
</summary>
<param name="box">AIOBOX</param>
<param name="sta">所有DO状态</param>
</member>
<member name="E:Asa.IOModule.AIOBOX.DO_Changed_Event">
<summary>
自动读取DO事件触发
</summary>
</member>
<member name="M:Asa.IOModule.AIOBOX.#ctor">
<summary>
AIOBOX
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.IP">
<summary>
IP地址
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.Mask">
<summary>
子网掩码
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.Gateway">
<summary>
子网网关
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.Port">
<summary>
ModBus端口
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.IsConn">
<summary>
是否连接
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.ErrInfo">
<summary>
错误信息
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.AutoReadDI">
<summary>
自动读取DI状态,触发DI_Changed_Event
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.AutoReadDO">
<summary>
自动读取DO状态,触发DO_Changed_Event
</summary>
</member>
<member name="P:Asa.IOModule.AIOBOX.Type">
<summary>
IO模块类型
</summary>
</member>
<member name="M:Asa.IOModule.AIOBOX.Connect">
<summary>
连接
</summary>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.Close">
<summary>
关闭连接
</summary>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReverseStatus(Asa.IOModule.Box_Sta)">
<summary>
相反状态
</summary>
<param name="sta"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReadDI(Asa.IOModule.Box_Addr)">
<summary>
读取单个DI
</summary>
<param name="add"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReadDI(Asa.IOModule.Box_Addr,System.Int32)">
<summary>
读取多个DI
</summary>
<param name="add"></param>
<param name="count"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReadDO(Asa.IOModule.Box_Addr)">
<summary>
读取单个DO
</summary>
<param name="add"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReadDO(Asa.IOModule.Box_Addr,System.Int32)">
<summary>
读取多个DO
</summary>
<param name="add"></param>
<param name="count"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.WriteDO(Asa.IOModule.Box_Addr,Asa.IOModule.Box_Sta)">
<summary>
写入单个DO
</summary>
<param name="add"></param>
<param name="sta"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.WriteDO_Reverse(Asa.IOModule.Box_Addr,Asa.IOModule.Box_Sta@)">
<summary>
先把状态取反,然后写入单个DO
</summary>
<param name="add"></param>
<param name="sta"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.WriteDO(Asa.IOModule.Box_Addr,Asa.IOModule.Box_Sta[])">
<summary>
写入多个DO
</summary>
<param name="add"></param>
<param name="sta"></param>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.Command(System.Byte[]@)">
<summary>
命令,前7个字节
</summary>
<param name="data"></param>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReadDI">
<summary>
读取所有DI状态
</summary>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.ReadDO">
<summary>
读取所有DO状态
</summary>
<returns></returns>
</member>
<member name="M:Asa.IOModule.AIOBOX.Target(System.IAsyncResult)">
<summary>
回调函数,开启监听线程
</summary>
<param name="args"></param>
</member>
<member name="M:Asa.IOModule.AIOBOX.Listen">
<summary>
监听结果线程,把读取到的数据保存到buff
</summary>
</member>
<member name="M:Asa.IOModule.AIOBOX.Trigger_DIO">
<summary>
触发DIO改变事件
</summary>
</member>
<member name="M:Asa.IOModule.AIOBOX.Auto_Read_DIO">
<summary>
自动读取DIO线程
</summary>
</member>
<member name="T:Asa.IOModule.Reg">
<summary>
IO模块寄存器
</summary>
</member>
<member name="F:Asa.IOModule.Reg.ID">
<summary>
标识
</summary>
</member>
<member name="F:Asa.IOModule.Reg.Text">
<summary>
文本,仅用于显示
</summary>
</member>
<member name="F:Asa.IOModule.Reg.Address">
<summary>
寄存器地址
</summary>
</member>
<member name="F:Asa.IOModule.Reg.Status">
<summary>
当前的状态
</summary>
</member>
<member name="M:Asa.IOModule.Reg.#ctor(Asa.IOModule.Box_Addr)">
<summary>
寄存器,文本空,状态OFF
</summary>
<param name="address">地址</param>
</member>
<member name="M:Asa.IOModule.Reg.#ctor(System.String,Asa.IOModule.Box_Addr)">
<summary>
寄存器,状态OFF
</summary>
<param name="text">文本</param>
<param name="addr">地址</param>
</member>
<member name="M:Asa.IOModule.Reg.#ctor(System.Int32,System.String,Asa.IOModule.Box_Addr)">
<summary>
寄存器,状态OFF
</summary>
<param name="id">标志</param>
<param name="text">文本</param>
<param name="addr">地址</param>
</member>
<member name="M:Asa.IOModule.Reg.#ctor(System.String,Asa.IOModule.Box_Addr,Asa.IOModule.Box_Sta)">
<summary>
寄存器
</summary>
<param name="text">文本</param>
<param name="addr">地址</param>
<param name="status">状态</param>
</member>
<member name="M:Asa.IOModule.Reg.#ctor(System.Int32,System.String,Asa.IOModule.Box_Addr,Asa.IOModule.Box_Sta)">
<summary>
寄存器
</summary>
<param name="id">标志</param>
<param name="text">文本</param>
<param name="address">地址</param>
<param name="status">状态</param>
</member>
<member name="T:Asa.IOModule.Box_Addr">
<summary>
IO模块寄存器地址
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_1">
<summary>
输入点,DI01
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_2">
<summary>
输入点,DI02
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_3">
<summary>
输入点,DI03
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_4">
<summary>
输入点,DI04
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_5">
<summary>
输入点,DI05
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_6">
<summary>
输入点,DI06
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_7">
<summary>
输入点,DI07
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_8">
<summary>
输入点,DI08
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_9">
<summary>
输入点,DI09
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_10">
<summary>
输入点,DI10
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_11">
<summary>
输入点,DI11
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_12">
<summary>
输入点,DI12
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_13">
<summary>
输入点,DI13
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_14">
<summary>
输入点,DI14
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_15">
<summary>
输入点,DI15
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DI_16">
<summary>
输入点,DI16
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_1">
<summary>
输出点,DO01
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_2">
<summary>
输出点,DO02
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_3">
<summary>
输出点,DO03
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_4">
<summary>
输出点,DO04
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_5">
<summary>
输出点,DO05
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_6">
<summary>
输出点,DO06
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_7">
<summary>
输出点,DO07
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_8">
<summary>
输出点,DO08
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_9">
<summary>
输出点,DO09
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_10">
<summary>
输出点,DO10
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_11">
<summary>
输出点,DO11
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_12">
<summary>
输出点,DO12
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_13">
<summary>
输出点,DO13
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_14">
<summary>
输出点,DO14
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_15">
<summary>
输出点,DO15
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.DO_16">
<summary>
输出点,DO16
</summary>
</member>
<member name="F:Asa.IOModule.Box_Addr.NONE">
<summary>
</summary>
</member>
<member name="T:Asa.IOModule.Box_Type">
<summary>
IO模块类型
</summary>
</member>
<member name="F:Asa.IOModule.Box_Type.DIO_16">
<summary>
16位,8DI + 8DO
</summary>
</member>
<member name="F:Asa.IOModule.Box_Type.DIO_32">
<summary>
32位,16DI + 16DO
</summary>
</member>
<member name="T:Asa.IOModule.Box_Sta">
<summary>
IO模块寄存器状态
</summary>
</member>
<member name="F:Asa.IOModule.Box_Sta.Off">
<summary>
断开,关闭,低电平
</summary>
</member>
<member name="F:Asa.IOModule.Box_Sta.On">
<summary>
闭合,打开,高电平
</summary>
</member>
</members>
</doc>
......@@ -110,7 +110,7 @@
this.groupBox1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.groupBox1.Location = new System.Drawing.Point(576, 11);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(437, 573);
this.groupBox1.Size = new System.Drawing.Size(437, 617);
this.groupBox1.TabIndex = 105;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "DO写入";
......@@ -493,7 +493,7 @@
// button1
//
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.button1.Location = new System.Drawing.Point(830, 590);
this.button1.Location = new System.Drawing.Point(830, 634);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(115, 34);
this.button1.TabIndex = 254;
......@@ -508,7 +508,7 @@
this.chbAutoRead.Checked = true;
this.chbAutoRead.CheckState = System.Windows.Forms.CheckState.Checked;
this.chbAutoRead.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.chbAutoRead.Location = new System.Drawing.Point(706, 595);
this.chbAutoRead.Location = new System.Drawing.Point(706, 639);
this.chbAutoRead.Name = "chbAutoRead";
this.chbAutoRead.Size = new System.Drawing.Size(75, 21);
this.chbAutoRead.TabIndex = 244;
......@@ -522,7 +522,7 @@
this.groupBox4.Controls.Add(this.tableLayoutPanel2);
this.groupBox4.Location = new System.Drawing.Point(293, 8);
this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(273, 621);
this.groupBox4.Size = new System.Drawing.Size(273, 665);
this.groupBox4.TabIndex = 104;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "DO列表";
......@@ -539,7 +539,7 @@
this.tableLayoutPanel2.RowCount = 2;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(262, 601);
this.tableLayoutPanel2.Size = new System.Drawing.Size(262, 645);
this.tableLayoutPanel2.TabIndex = 103;
//
// groupBox3
......@@ -549,7 +549,7 @@
this.groupBox3.Controls.Add(this.tableLayoutPanel1);
this.groupBox3.Location = new System.Drawing.Point(12, 8);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(273, 621);
this.groupBox3.Size = new System.Drawing.Size(273, 665);
this.groupBox3.TabIndex = 103;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "DI列表";
......@@ -566,14 +566,14 @@
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 17F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(262, 601);
this.tableLayoutPanel1.Size = new System.Drawing.Size(262, 645);
this.tableLayoutPanel1.TabIndex = 102;
//
// FrmIOStatus
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1036, 639);
this.ClientSize = new System.Drawing.Size(1036, 683);
this.Controls.Add(this.button1);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.groupBox4);
......
......@@ -240,7 +240,7 @@ namespace OnlineStore.AutoInOutStore
{
cmbJianGe.Items.Add(i.ToString());
}
cmbJianGe.SelectedIndex = 0;
cmbJianGe.SelectedIndex = 1;
DebugStatus(false);
}
......@@ -1710,7 +1710,6 @@ namespace OnlineStore.AutoInOutStore
DialogResult res = MessageBox.Show("确定开始自动出入库?", "提示", MessageBoxButtons.YesNo);
if (res.Equals(DialogResult.Yes))
{
store.autoNext = true;
int jiange = cmbJianGe.SelectedIndex;
store.autoJiange = jiange;
if (cmbPosition.SelectedIndex >= 0)
......@@ -1724,7 +1723,8 @@ namespace OnlineStore.AutoInOutStore
store.autoMsg = "自动入库:" + poText;
string msg = AutomaticBaiting.doStartBatchIn();
if (msg.Equals(""))
{
{
store.autoNext = true;
btnStart.Text = StopAuto;
LogUtil.info(LOGGER, store.StoreName + "开启自动出入库模式,开始位置【" + poText + "】(索引=" + currIndex + "),间隔=" + jiange + ",入库开始!");
}
......
......@@ -155,7 +155,8 @@ PRO,最后一盘料需要补充的高度,LastTrayAddHeight,10,,,,,,,,,
20190505
温湿度报警功能修改:报警时在界面显示提示。
批量上料轴极限信号改为IODI27。
批量上下料功能修改。
......
......@@ -81,8 +81,12 @@ namespace OnlineStore.Common
return null;
}
public static int isLog = ConfigAppSettings.GetIntValue(Setting_Init.Server_Log_Open);
public static string Post(string url, string paramData, Encoding encoding)
public static string Post(string url, string paramData="", Encoding encoding=null)
{
if (encoding == null)
{
encoding = Encoding.UTF8;
}
if (isLog == 1)
{
LOGGER.Info("给服务器发送数据【" + paramData + "】 ");
......
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using OnlineStore.Common;
using OnlineStore.LoadCSVLibrary;
using System.Threading.Tasks;
namespace OnlineStore.DeviceLibrary
{
public class AIOBOXManager : IOManager
{
//public static uint DefaultDICount = 16;
//public static uint DefaultDOCount = 16;
public readonly ILog LOGGER = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public Dictionary<string, AIOBOX> AIOMap = new Dictionary<string, AIOBOX>();
public string DefaultIP = "";
public Dictionary<string, List<Box_Sta>> DIValueMap = new Dictionary<string, List<Box_Sta>>();
public Dictionary<string, List<Box_Sta>> DOValueMap = new Dictionary<string, List<Box_Sta>>();
private object DIMapLock = "";
private object DOMapLock = "";
public System.Timers.Timer timer = null;
private object DILock = "";
private object DOLock = "";
public void ConnectionIP(string ioIp )
{
AIOBOX aioBox = null;
if (AIOMap.ContainsKey(ioIp))
{
aioBox = AIOMap[ioIp];
if (null != aioBox)
{
aioBox.Close();
aioBox = null;
}
AIOMap.Remove(ioIp);
}
if (DIValueMap.ContainsKey(ioIp))
{
DIValueMap.Remove(ioIp);
}
if (DOValueMap.ContainsKey(ioIp))
{
DOValueMap.Remove(ioIp);
}
try
{
// Create new modbus master and add event functions
aioBox = new AIOBOX();
aioBox.IP = ioIp;
DefaultIP = ioIp;
aioBox.AutoReadDI = true;
aioBox.AutoReadDO = true;
if (StoreManager.Config.GetDILength(ioIp).Equals(8))
{
aioBox.Type = Box_Type.DIO_16;
}
else
{
aioBox.Type = Box_Type.DIO_32;
}
aioBox.DI_Changed_Event += AioBox_DI_Changed_Event; ;
aioBox.DO_Changed_Event += AioBox_DO_Changed_Event;
LogUtil.info("开始连接IO模块【" + ioIp + "】,尝试重连三次");
for (int i = 1; i <= 3; i++)
{
bool result = aioBox.Connect();
if (result)
{
AIOMap.Add(ioIp, aioBox);
LogUtil.info("第【"+i+"】次连接IO模块【" + ioIp + "】成功:" + aioBox.ErrInfo);
Thread.Sleep(10);
//读取所有的DO
ReadAllDI(ioIp, 0);
break;
}
else
{
LogUtil.error("第【" + i + "】次连接IO模块【" + ioIp + "】失败:" + aioBox.ErrInfo + "");
}
Thread.Sleep(10);
}
}
catch (Exception error)
{
LogUtil.error(LOGGER, "连接IO模块[" + ioIp + "]出错:" + error.ToString());
}
}
private void AioBox_DI_Changed_Event(AIOBOX box, Box_Sta[] sta)
{
try
{
UpdateAllDI(box.IP, sta);
}
catch (Exception ex)
{
LogUtil.error("AioBox_DI_Changed_Event出错:" + ex.ToString());
}
}
private void AioBox_DO_Changed_Event(AIOBOX box, Box_Sta[] sta)
{
try
{
UpdateAllDO(box.IP, sta);
}
catch (Exception ex)
{
LogUtil.error("AioBox_DO_Changed_Event出错:" + ex.ToString());
}
}
private void UpdateAllDI(string ip, Box_Sta[] sta)
{
if (sta != null && sta.Length >= StoreManager.Config.GetDILength(ip))
{
bool needUpdate = false;
List<Box_Sta> newList = new List<Box_Sta>();
newList.AddRange(sta);
List<Box_Sta> oldList = null;
DIValueMap.TryGetValue(ip, out oldList);
if (oldList == null || oldList.Count.Equals(newList.Count).Equals(false))
{
needUpdate = true;
}
else
{
for (int i = 0; i < newList.Count; i++)
{
if (!(oldList[i].Equals(newList[i])))
{
needUpdate = true;
break;
}
}
}
if (needUpdate)
{
lock (DILock)
{
if (DIValueMap.ContainsKey(ip))
{
DIValueMap.Remove(ip);
}
DIValueMap.Add(ip, newList);
}
}
}
}
private void UpdateAllDO(string ip, Box_Sta[] sta)
{
if (sta != null && sta.Length >= StoreManager.Config.GetDOLength(ip))
{
bool needUpdate = false;
List<Box_Sta> newList = new List<Box_Sta>();
newList.AddRange(sta);
List<Box_Sta> oldList = null;
DOValueMap.TryGetValue(ip, out oldList);
if (oldList == null || oldList.Count.Equals(newList.Count).Equals(false))
{
needUpdate = true;
}
else
{
for (int i = 0; i < newList.Count; i++)
{
if (!(oldList[i].Equals(newList[i])))
{
needUpdate = true;
break;
}
}
}
if (needUpdate)
{
lock (DOLock)
{
if (DOValueMap.ContainsKey(ip))
{
DOValueMap.Remove(ip);
}
DOValueMap.Add(ip, newList);
}
}
}
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
List<string> list = new List<string>(AIOMap.Keys);
foreach (string io in list)
{
//判断是否连接,如果没有连接自动重连
AIOBOX clinet = AIOMap[io];
if (!clinet.IsConn)
{
LogUtil.error(LOGGER, io + "当前没有连上:" + clinet.ErrInfo);
}
}
}
catch (Exception ex)
{
LogUtil.error(LOGGER, "出错啦:" + ex.ToString());
}
Thread.Sleep(1);
}
public override void ConnectionIOList(List<string> DIONameList)
{
foreach (string ip in DIONameList)
{
ConnectionIP(ip );
}
}
//关闭所有的DO
public override void CloseAllDO()
{
foreach (AIOBOX aio in AIOMap.Values)
{
Box_Sta[] Box_Staes = new Box_Sta[16];
for(int i = 0; i < 16; i++)
{
Box_Staes[i] = Box_Sta.Off;
}
aio.WriteDO( Box_Addr.DI_1, Box_Staes);
}
}
public override void CloseAllConnection()
{
foreach (AIOBOX aio in AIOMap.Values)
{
aio.Close();
}
AIOMap.Clear();
}
public override void WriteSingleDO(string ioIp, byte slaveId, ushort StartAddress, IO_VALUE onOff)
{
try
{
AIOBOX aioBox = getAIO(ioIp);
if (aioBox != null)
{
Box_Addr add = GetAddr(StartAddress);
for (int i = 1; i <= 3; i++)
{
bool result = aioBox.WriteDO(GetAddr(StartAddress), GetBox_Sta(onOff));
if (!result)
{
LogUtil.error("AIO WriteSingleDO [" + StartAddress + "] 第" + i + "次失败:" + aioBox.ErrInfo);
}
else
{
break;
}
}
}
else
{
LogUtil.error(LOGGER, "ReadSingleDO出错没有连接IO模块:" + ioIp);
}
}
catch (Exception ex)
{
LOGGER.Error("出错啦:" + ex.ToString());
}
}
public override void WriteSingleDO(string ioIp, byte slaveId, ushort StartAddress, IO_VALUE onOff, int mSeconds)
{
try
{
AIOBOX aioBox = getAIO(ioIp);
Box_Sta currBox_Sta = GetBox_Sta(onOff);
if (aioBox != null)
{
Box_Addr add = GetAddr(StartAddress);
aioBox.WriteDO(GetAddr(StartAddress), currBox_Sta);
//写入之后,等待指定间隔后回写
System.Timers.Timer mytimer = new System.Timers.Timer(mSeconds);
mytimer.Elapsed += (o1, e1) =>
{
try
{
aioBox.WriteDO(GetAddr(StartAddress), aioBox.ReverseStatus(currBox_Sta));
LogUtil.debug(LOGGER, "**********定时回写入 IO【" + ioIp + "," + StartAddress + ",值" + aioBox.ReverseStatus(currBox_Sta) + "】:");
}
catch (Exception ex)
{
LogUtil.error(LOGGER, "**********定时回写入 出错:" + ex.StackTrace);
}
};
mytimer.AutoReset = false;//设置是否自动重启,即自动执行多次;
mytimer.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件mytask;
}
else
{
LogUtil.error(LOGGER, "WriteSingleDO出错没有连接IO模块:" + ioIp);
}
}
catch (Exception ex)
{
LogUtil.error("WriteSingleDO出错:" + ioIp);
}
}
public override void ReadAllDI(string ioIp, byte slaveId)
{
try
{
AIOBOX aioBox = getAIO(ioIp);
if (aioBox != null)
{
Box_Sta[] allDi = aioBox.ReadDI(Box_Addr.DI_1, StoreManager.Config.GetDILength(ioIp));
UpdateAllDI(ioIp, allDi);
}
}
catch (Exception ex)
{
LogUtil.error("ReadAllDI出错:" + ioIp);
}
}
public override void ReadAllDO(string ioIp, byte slaveId)
{
try
{
AIOBOX aioBox = getAIO(ioIp);
if (aioBox != null)
{
Box_Sta[] allDO = aioBox.ReadDO(Box_Addr.DO_1, StoreManager.Config.GetDOLength(ioIp));
UpdateAllDO(ioIp, allDO);
}
}
catch (Exception ex)
{
LogUtil.error("ReadAllDO出错:" + ioIp);
}
}
public override IO_VALUE GetDOValue(string ioIP, byte slaveId, ushort StartAddress)
{
IO_VALUE value = IO_VALUE.LOW;
try
{
AIOBOX aioBox = getAIO(ioIP);
if (aioBox != null)
{
Box_Sta sta = Box_Sta.Off;
Box_Addr addr = GetAddr(StartAddress);
int index = (int)StartAddress - (int)StoreManager.Config.GetDILength(ioIP);
if (DOValueMap.ContainsKey(ioIP) && DOValueMap[ioIP].Count > index)
{
sta = DOValueMap[ioIP][index];
}
else
{ sta = aioBox.ReadDO(addr); }
if (sta.Equals(Box_Sta.On))
{
value = IO_VALUE.HIGH;
}
}
}
catch (Exception ex)
{
LogUtil.error("ReadDI 出错:" + ex.ToString());
}
return value;
}
public override IO_VALUE GetDIValue(string ioIP, byte slaveId, ushort StartAddress)
{
IO_VALUE value = IO_VALUE.LOW;
try
{
AIOBOX aioBox = getAIO(ioIP);
if (aioBox != null)
{
Box_Sta sta = Box_Sta.Off;
Box_Addr addr = GetAddr(StartAddress);
int index = StartAddress;
if (DIValueMap.ContainsKey(ioIP) && DIValueMap[ioIP].Count> index)
{
sta = DIValueMap[ioIP][index];
}
else
{
sta= aioBox.ReadDI(addr );
}
if (sta.Equals(Box_Sta.On))
{
value = IO_VALUE.HIGH;
}
}
}
catch (Exception ex)
{
LogUtil.error("ReadDI 出错:" + ex.ToString());
}
return value;
}
public override IO_VALUE GetIOValue(ConfigIO configIO)
{
IO_VALUE value = IO_VALUE.LOW;
try
{
if (configIO.ProType.Equals(ConfigItemType.DI))
{
return GetDIValue(configIO.DeviceName, configIO.SlaveID, configIO.GetIOAddr());
}
else if (configIO.ProType.Equals(ConfigItemType.DO))
{
return GetDOValue(configIO.DeviceName, configIO.SlaveID, configIO.GetIOAddr());
}
}
catch (Exception ex)
{
LogUtil.error(LOGGER, "获取数据出错:" + ex.ToString());
}
return value;
}
private Box_Addr GetAddr(ushort StartAddress)
{
return (Box_Addr)(StartAddress );
}
private Box_Sta GetBox_Sta(IO_VALUE onOff)
{
if (onOff.Equals(IO_VALUE.HIGH))
{
return Box_Sta.On;
}
else
{
return Box_Sta.Off;
}
}
private AIOBOX getAIO(string ioIp)
{
AIOBOX aioBox = null;
if (AIOMap.ContainsKey(ioIp))
{
aioBox = AIOMap[ioIp];
}
return aioBox;
}
}
}
......@@ -192,7 +192,10 @@ namespace OnlineStore.DeviceLibrary
}
public static void SuddenStop(ConfigMoveAxis axis)
{
SuddenStop(axis.DeviceName, axis.GetAxisValue());
if (GetBusyStatus(axis.DeviceName, axis.GetAxisValue()).Equals(1))
{
SuddenStop(axis.DeviceName, axis.GetAxisValue());
}
}
public static void SuddenStop(string portName, int slvAddr)
{
......
......@@ -47,18 +47,18 @@ namespace OnlineStore.DeviceLibrary
IsInProcess = true;
bool result = false;
if (IOManager.IOValue(TargetIoType).Equals(IO_VALUE.HIGH))
{
LogUtil.info("批量上料轴,检测到【" + TargetIoType + "】信号,可以停止运动");
{
LogUtil.info("批量上料轴,检测到【" + TargetIoType + "】信号,可以停止运动");
result = true;
}
TimeSpan span = DateTime.Now - preTime;
if (span.TotalMilliseconds > 100)
//TimeSpan span = DateTime.Now - preTime;
//if (span.TotalMilliseconds > 100)
//{
else if (IOManager.IOValue(IO_Type.BatchAxis_Limit).Equals(IO_VALUE.HIGH))
//if (ACServerManager.GetLimitPositiveSingle(StoreManager.Config.Batch_Axis).Equals(1))
{
if (ACServerManager.GetLimitPositiveSingle(StoreManager.Config.Batch_Axis).Equals(1))
{
LogUtil.info("批量上料轴,检测到正极限信号,可以停止运动");
result = true;
}
LogUtil.info("批量上料轴,检测到正极限信号,可以停止运动");
result = true;
}
if (result)
{
......
......@@ -37,7 +37,7 @@ DI,吸盘压力确认信号,SuckingDisc_Air,2,192.168.200.12,0,吸盘压力确认信号,X23,DI-2
DI,左侧门关闭,DoorColse_Single,3,192.168.200.12,0,左侧门关闭,X24,DI-24,0,
DI,门锁气缸打开端2,BatchDoor_Open2,4,192.168.200.12,0,门锁气缸打开端2,X25,DI-25,0,
DI,门锁气缸关闭端2,BatchDoor_Close2,5,192.168.200.12,0,门锁气缸关闭端2,X26,DI-26,0,
,,,6,192.168.200.12,0,,X27,DI-27,0,
DI,批量轴极限信号,BatchAxis_Limit,6,192.168.200.12,0,批量轴极限信号,X27,DI-27,0,
,,,7,192.168.200.12,0,,X28,DI-28,0,
,,,16,192.168.200.12,0,,Y21,DO-21,0,
,,,17,192.168.200.12,0,,Y22,DO-22,0,
......
......@@ -1138,6 +1138,14 @@ namespace OnlineStore.DeviceLibrary
return;
}
preProTime = DateTime.Now;
if (!AutomaticBaiting.CanOpenBatchDoor())
{
return;
}
if (!CanStarInOut())
{
return;
}
if (CurrInOutACount >= this.Config.Box_ResetACount)
{
if (storeRunStatus < StoreRunStatus.Runing || StoreMove.MoveType == StoreMoveType.InStore || StoreMove.MoveType == StoreMoveType.OutStore)
......@@ -1150,18 +1158,18 @@ namespace OnlineStore.DeviceLibrary
Reset();
}
}
else if (CurrInOutCount >= this.Config.Box_ResetMCount)
{
if (storeRunStatus < StoreRunStatus.Runing || StoreMove.MoveType == StoreMoveType.InStore || StoreMove.MoveType == StoreMoveType.OutStore)
{
LogUtil.info(LOGGER, StoreName + "已经累计出入库" + CurrInOutCount + "次,当时当前正在忙碌中暂不复位旋转轴");
}
else
{
LogUtil.info(LOGGER, StoreName + "已经累计出入库" + CurrInOutCount + "次,需要复位一下旋转轴");
}
}
else
//else if (CurrInOutCount >= this.Config.Box_ResetMCount)
//{
// if (storeRunStatus < StoreRunStatus.Runing || StoreMove.MoveType == StoreMoveType.InStore || StoreMove.MoveType == StoreMoveType.OutStore)
// {
// LogUtil.info(LOGGER, StoreName + "已经累计出入库" + CurrInOutCount + "次,当时当前正在忙碌中暂不复位旋转轴");
// }
// else
// {
// LogUtil.info(LOGGER, StoreName + "已经累计出入库" + CurrInOutCount + "次,需要复位一下旋转轴");
// }
//}
else if (waitOutStoreList.Count > 0 && CanStarInOut())
{
FixtureCodeInfo currInOutFixture = null;
lock (waitOutListLock)
......@@ -1172,19 +1180,53 @@ namespace OnlineStore.DeviceLibrary
waitOutStoreList.RemoveAt(0);
}
}
if (currInOutFixture != null)
if (currInOutFixture != null && currInOutFixture.WareNum.Equals(""))
{ //出库
if (currInOutFixture.WareNum.Equals(""))
LogUtil.info(LOGGER, StoreName + "开始执行排队中的出库【" + currInOutFixture.ToStr() + "】");
bool result = StartOutStoreMove(new InOutStoreParam("", currInOutFixture.PosId, currInOutFixture.plateH, currInOutFixture.plateW), currInOutFixture.BatchInOut);
if (!result)
{
LogUtil.info(LOGGER, StoreName + "开始执行排队中的出库【" + currInOutFixture.ToStr() + "】");
bool result = StartOutStoreMove(new InOutStoreParam("", currInOutFixture.PosId, currInOutFixture.plateH, currInOutFixture.plateW), currInOutFixture.BatchInOut);
if (!result)
LogUtil.info(LOGGER, StoreName + " 执行排队中的出库【" + currInOutFixture.ToStr() + "】失败,重新加入等待队列");
AddWaitOutInfo(currInOutFixture);
}
}
}
else if (autoNext && CanStarInOut() )
{
//获取出库的库位号
string readId = "";
//http://[SMD-BOX-IP]:[SMD-BOX-Port]/rest/api/v2/mes/inventory
string result = HttpHelper.Post(StoreManager.GetAPI("", StoreManager.api_inventory));
if (!String.IsNullOrEmpty(result))
{
string[] rArray = result.Split('}');
foreach (string obj in rArray)
{
string[] objArray = obj.Split(',');
if (objArray.Length >= 4)
{
LogUtil.info(LOGGER, StoreName + " 执行排队中的出库【" + currInOutFixture.ToStr() + "】失败,重新加入等待队列");
AddWaitOutInfo(currInOutFixture);
string rId = objArray[1];
if (rId.Length > 7)
{
readId = rId.Substring(6, rId.Length - 7);
LogUtil.info("自动出入库:查找到:RI: " + readId );
break;
}
}
}
}
if (readId.Equals(""))
{
//开始自动入库
string msg = AutomaticBaiting.doStartBatchIn();
LogUtil.info("自动出入库:库位号【" + GetAutoPosid(false) + "】,开始入库" + msg);
}
else
{
autoMsg = "自动出库:RI:" + readId;
result = HttpHelper.Post(StoreManager.GetAPI("", StoreManager.api_stackOut)+ "?RIS=" + readId);
LogUtil.info("自动出入库:自动出库:RI: " + readId + " ," + result);
}
}
}
catch (Exception ex)
......@@ -1264,11 +1306,11 @@ namespace OnlineStore.DeviceLibrary
return isInAlarm;
}
public void AxisSuddenStop()
{
ACServerManager.SuddenStop(Config.Middle_Axis.DeviceName, Config.Middle_Axis.GetAxisValue());
ACServerManager.SuddenStop(Config.UpDown_Axis.DeviceName, Config.UpDown_Axis.GetAxisValue());
ACServerManager.SuddenStop(Config.InOut_Axis.DeviceName, Config.InOut_Axis.GetAxisValue());
ACServerManager.SuddenStop(Config.Batch_Axis.DeviceName, Config.Batch_Axis.GetAxisValue());
{
ACServerManager.SuddenStop(Config.Middle_Axis);
ACServerManager.SuddenStop(Config.UpDown_Axis);
ACServerManager.SuddenStop(Config.InOut_Axis);
ACServerManager.SuddenStop(Config.Batch_Axis);
}
public override void StopMove(bool IsCloseAxis)
{
......@@ -1796,10 +1838,10 @@ namespace OnlineStore.DeviceLibrary
bool result = StartOutStoreMove(new InOutStoreParam("", posId, plateH, plateW), !isSingleOut);
if (!result)
{
LogUtil.info(LOGGER, StoreName + " 执行出库【" + currInOutFixture.ToStr() + "】失败,加入等待队列");
AddWaitOutInfo(currInOutFixture);
}
if(autoNext) autoMsg = "自动出库:" + posId;
}
else
{
......
......@@ -998,6 +998,29 @@ namespace OnlineStore.DeviceLibrary
}
#region 自动出入库循环代码
public string GetAutoPosid(bool isNext)
{
string posid = "";
if (autoNext)
{
if (PositionNumList.Count > autoPositionIndex)
{
posid = PositionNumList[autoPositionIndex];
autoMsg = "自动入库:" +posid;
//到下一个库位
if (isNext)
{
int newIndex = autoPositionIndex - autoJiange;
if (newIndex < 0)
{
newIndex = AutoStartIndex;
}
autoPositionIndex = newIndex;
}
}
}
return posid;
}
private void InOutEndProcess(StoreMoveType storeMoveType)
{
try
......@@ -1005,38 +1028,38 @@ namespace OnlineStore.DeviceLibrary
CurrInOutCount++;
CurrInOutACount++;
//是否自动进入出库状态
if (!autoNext)
{
return;
}
if (storeMoveType.Equals(StoreMoveType.InStore))
{
string posid = PositionNumList[autoPositionIndex];
//if (!autoNext)
//{
// return;
//}
//if (storeMoveType.Equals(StoreMoveType.InStore))
//{
// string posid = PositionNumList[autoPositionIndex];
autoMsg = "自动出库:" + posid;
//自动出入口,入库结束把出库加入队列
FixtureCodeInfo currInOutFixture = new FixtureCodeInfo(0, "", posid);
AddWaitOutInfo(currInOutFixture);
LogUtil.info("自动出入口,入库结束,将库位号【"+ posid + "】加入出库等待中");
}
else if (storeMoveType.Equals(StoreMoveType.OutStore))
{
int newIndex = autoPositionIndex - autoJiange;
if (newIndex < 0)
{
newIndex = AutoStartIndex;
}
else
{
autoPositionIndex = newIndex;
string posid = PositionNumList[newIndex];
ConfigAppSettings.SaveValue(Setting_Init.DebugPosId, posid);
//开始自动入库
autoMsg = "自动入库:" + posid;
string msg = AutomaticBaiting.doStartBatchIn();
LogUtil.info("自动出入库:库位号【"+posid+"】,开始入库"+msg);
}
}
// autoMsg = "自动出库:" + posid;
// //自动出入口,入库结束把出库加入队列
// FixtureCodeInfo currInOutFixture = new FixtureCodeInfo(0, "", posid);
// AddWaitOutInfo(currInOutFixture);
// LogUtil.info("自动出入口,入库结束,将库位号【"+ posid + "】加入出库等待中");
//}
//else if (storeMoveType.Equals(StoreMoveType.OutStore))
//{
// int newIndex = autoPositionIndex - autoJiange;
// if (newIndex < 0)
// {
// newIndex = AutoStartIndex;
// }
// else
// {
// autoPositionIndex = newIndex;
// string posid = PositionNumList[newIndex];
// ConfigAppSettings.SaveValue(Setting_Init.DebugPosId, posid);
// //开始自动入库
// autoMsg = "自动入库:" + posid;
// string msg = AutomaticBaiting.doStartBatchIn();
// LogUtil.info("自动出入库:库位号【"+posid+"】,开始入库"+msg);
// }
//}
}
catch (Exception ex)
{
......
......@@ -667,8 +667,8 @@ namespace OnlineStore.DeviceLibrary
else if (StoreMove.MoveStep.Equals(StoreMoveStep.AUTO_O03_SpeedMove))
{
//先判断极限是否亮
int value = ACServerManager.GetLimitPositiveSingle(StoreManager.Config.Batch_Axis);
if (value.Equals(1))
//int value = ACServerManager.GetLimitPositiveSingle(StoreManager.Config.Batch_Axis);
if (IOManager.IOValue(IO_Type.BatchAxis_Limit).Equals(IO_VALUE.HIGH))
{
StoreMove.NextMoveStep(StoreMoveStep.AUTO_O05_BackToP2);
LogUtil.info(Name + "出料:上料轴移动到p2点【" + StoreManager.Config.BatchAxis_P2 + "】");
......
......@@ -232,7 +232,8 @@ namespace OnlineStore.DeviceLibrary
LogUtil.info(wait.ToStr() + " 检测到【" + wait.IoType + "】信号,可以停止运动");
result = true;
}
else if (ACServerManager.GetLimitPositiveSingle(wait.AxisInfo).Equals(1))
else if (IOManager.IOValue(IO_Type.BatchAxis_Limit).Equals(IO_VALUE.HIGH))
//else if (ACServerManager.GetLimitPositiveSingle(wait.AxisInfo).Equals(1))
{
LogUtil.info(wait.ToStr() + " 检测到正极限信号,可以停止运动");
ACServerManager.SuddenStop(wait.AxisInfo.DeviceName, wait.AxisInfo.GetAxisValue());
......@@ -275,7 +276,7 @@ namespace OnlineStore.DeviceLibrary
}
LastCodeList = hasList;
LastCode = message;
if (LastCode.Equals("") && (StoreManager.Store.IsDebug || StoreManager.Store.autoNext))
if (LastCode.Equals("") && (StoreManager.Store.IsDebug ))
{
LastCode = "NoCode";
LogUtil.info(Name + "模拟二维码:NoCode");
......@@ -331,8 +332,9 @@ namespace OnlineStore.DeviceLibrary
{
try
{
if (StoreManager.Store.IsDebug || StoreManager.Store.autoNext)
{
//if (StoreManager.Store.IsDebug || StoreManager.Store.autoNext)
if (StoreManager.Store.IsDebug )
{
string posId = ConfigAppSettings.GetValue(Setting_Init.DebugPosId);
if (!posId.Equals(""))
{
......@@ -380,6 +382,7 @@ namespace OnlineStore.DeviceLibrary
LogUtil.info(Name + "收到二维码【 " + message + "】,发送给服务器获取入库PosID");
//发送扫码内容到服务器进行入库操作
Operation operation = StoreManager.Store.getLineBoxStatus();
operation.op = 1;
if (operation.data == null)
{
......@@ -387,13 +390,15 @@ namespace OnlineStore.DeviceLibrary
}
operation.data.Add("code", message);
operation.data.Add("boxId", StoreManager.Store.StoreID.ToString());
//{ { "code", message }, { "boxId", StoreManager.Store.StoreID.ToString() } };
string autoposId = StoreManager.Store.GetAutoPosid(true);
if (StoreManager.Store.autoNext && (!String.IsNullOrEmpty(autoposId)))
{
operation.data.Add(ParamDefine.posId, autoposId);
LogUtil.info("添加自动入库库位号:"+autoposId);
}
string server = ConfigAppSettings.GetValue(Setting_Init.http_server);
Operation resultOperation = HttpHelper.Post(StoreManager.GetPostApi(server), operation, false);
//HttpHelper.isLog = ConfigAppSettings.GetIntValue(Setting_Init.Server_Log_Open);
if (resultOperation == null)
{
// CodeMsg = "二维码【" + message + "】没有收到服务器反馈";
......@@ -403,7 +408,7 @@ namespace OnlineStore.DeviceLibrary
else if (!string.IsNullOrEmpty(resultOperation.msg))
{
//如果有提示消息,直接显示提示
LogUtil.info(Name + "服务器反馈 二维码【" + message + "】 :" + resultOperation.msg);
LogUtil.info(Name + "服务器反馈 二维码【" + message + "】【"+ autoposId + "】 :" + resultOperation.msg);
return;
}
Dictionary<string, string> data = resultOperation.data;
......@@ -423,8 +428,7 @@ namespace OnlineStore.DeviceLibrary
if (!(posArray.Length == 2))
{
WarnMsg = Name + ResourceControl.GetString(ResourceControl.InStoreError, "入库库位格式错误:") + "【" + message + "】【" + posId + "】";
LogUtil.error("服务器反馈 入库库位格式错误:二维码【" + message + "】库位【" + posId + "】");
LogUtil.info("服务器反馈 入库库位格式错误:二维码【" + message + "】库位【" + posId + "】");
LogUtil.error("服务器反馈 入库库位格式错误:二维码【" + message + "】库位【" + posId + "】");
return;
}
......
......@@ -23,6 +23,11 @@ namespace OnlineStore.DeviceLibrary
private static string api_communication = "service/store/communication"; //流水线状态通信接口
private static string api_nextFeeder = "service/store/nextFeeder"; // 出库站位列表切换接口
public static string api_inventory = "rest/api/v2/mes/inventory";//获取单个或全总SMD-BOX 中的实时库存信息
public static string api_stackOut = "rest/api/v2/mes/stackOut";//本接⼜提供物料出库功能,可⼀次性出单/多盘物料
public static readonly ILog LOGGER = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static AC_SA_BoxBean Store = null;
public static AUTO_SA_Config Config = null;
......@@ -144,22 +149,18 @@ namespace OnlineStore.DeviceLibrary
}
}
public static string GetPostApi(string host)
{
if (host == "")
{
host = ConfigAppSettings.GetValue(Setting_Init.http_server);
}
if (!host.StartsWith("http://"))
{
host = "http://" + host;
}
if (!host.EndsWith("/"))
{
host = host + "/";
}
{
host = GetHostUrl(host);
return host + api_communication;
}
public static string GetNextFeederApi(string host)
public static string GetAPI(string host, string api)
{
host = GetHostUrl(host);
return host + api;
}
private static string GetHostUrl(string host)
{
if (host == "")
{
......@@ -173,7 +174,7 @@ namespace OnlineStore.DeviceLibrary
{
host = host + "/";
}
return host + api_nextFeeder;
return host;
}
}
}
......@@ -199,5 +199,11 @@ namespace OnlineStore.LoadCSVLibrary
/// 报警蜂鸣器 Buzzer_Sign Y16
/// </summary>
public static string Buzzer_Sign = "Buzzer_Sign";
/// <summary>
/// DI 批量轴极限信号 BatchAxis_Limit
/// </summary>
public static string BatchAxis_Limit = "BatchAxis_Limit";
}
}
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!