|
@@ -0,0 +1,420 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Configuration;
|
|
|
+using System.Drawing;
|
|
|
+using System.IO;
|
|
|
+using System.Text;
|
|
|
+using System.Windows.Forms;
|
|
|
+using TwinCAT.Ads;
|
|
|
+
|
|
|
+namespace SIASUN.TwinCatLogger
|
|
|
+{
|
|
|
+ public partial class MainForm : Form
|
|
|
+ {
|
|
|
+ public MainForm()
|
|
|
+ {
|
|
|
+ InitializeComponent();
|
|
|
+ this.ShowInTaskbar = true;
|
|
|
+ this.WindowState = FormWindowState.Normal;
|
|
|
+ }
|
|
|
+
|
|
|
+ public string GetConfiguration(string key)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string value = System.Configuration.ConfigurationManager.AppSettings[key];
|
|
|
+ if (!string.IsNullOrEmpty(value))
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ catch (Exception ce)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ private void MainForm_Load(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ this.Visible = false;
|
|
|
+ this.notifyIcon1.Visible = true;
|
|
|
+ //this.skinEngine1.SkinFile = "EmeraldColor1.ssk"; //皮肤文件.ssk
|
|
|
+ runInDebug = GetConfiguration("测试模式").ToLower() == "true";
|
|
|
+ //try
|
|
|
+ //{
|
|
|
+ // AutoStartTask.CreateLogonTask(!runInDebug);
|
|
|
+ //}
|
|
|
+ //catch (Exception ex)
|
|
|
+ //{
|
|
|
+ // textNotice.Text = "创建开机自动启动任务失败:" + ex.Message;
|
|
|
+ //}
|
|
|
+ 小数位数 = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["小数位数"]);
|
|
|
+ 单文件行数 = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["单文件行数"]);
|
|
|
+ //LogonStart.CreateLogonTask(!runInDebug);
|
|
|
+ timer1.Interval = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["刷新时间"]);
|
|
|
+ if (LoadPointList())
|
|
|
+ timer2.Enabled = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
|
+ {
|
|
|
+ //e.Cancel = true; // 取消关闭窗体
|
|
|
+ //HideToolStripMenuItem_Click(sender, e);
|
|
|
+ if (MessageBox.Show("是否确认退出程序?", "退出", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
|
|
|
+ {
|
|
|
+ e.Cancel = false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ e.Cancel = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void MainForm_SizeChanged(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ if (WindowState == FormWindowState.Minimized)
|
|
|
+ {
|
|
|
+ HideToolStripMenuItem_Click(sender, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.Button == MouseButtons.Left)
|
|
|
+ {
|
|
|
+ OpenToolStripMenuItem_Click(sender, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void exitToolStripMenuItem_Click(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ exitToolStripMenuItem.Enabled = false;
|
|
|
+ this.Close();
|
|
|
+ exitToolStripMenuItem.Enabled = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void HideToolStripMenuItem_Click(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ this.Hide();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OpenToolStripMenuItem_Click(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ this.ShowInTaskbar = true;
|
|
|
+ this.Show();
|
|
|
+ this.WindowState = FormWindowState.Normal;
|
|
|
+ this.Activate();
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 数据
|
|
|
+ bool runInDebug = false;
|
|
|
+ int 小数位数 = 0;
|
|
|
+ int 单文件行数 = 0;
|
|
|
+ int 当前行数 = 0;
|
|
|
+
|
|
|
+ struct PlcPoint
|
|
|
+ {
|
|
|
+ public string name;
|
|
|
+ public string address;
|
|
|
+ public Type type;
|
|
|
+ }
|
|
|
+ List<PlcPoint> pointList = new List<PlcPoint>();
|
|
|
+ List<int> handleList = new List<int>();
|
|
|
+
|
|
|
+ private TcAdsClient adsClient = new TcAdsClient();
|
|
|
+ private string[] plcAdress = ConfigurationManager.AppSettings["PLC地址"].Split(':');
|
|
|
+ private int startSignal = 0;
|
|
|
+ private bool isRecording = false;
|
|
|
+ private bool isManuel = false;
|
|
|
+ private long stopWatch = 0;
|
|
|
+
|
|
|
+ private string filePrefix = "Log_";
|
|
|
+ private string filePath = "";
|
|
|
+ private StreamWriter fileWriter = null;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ private Type GetTypeByName(string typename)
|
|
|
+ {
|
|
|
+ if (typename.ToUpper() == "BOOL")
|
|
|
+ return typeof(bool);
|
|
|
+ if (typename.ToUpper() == "BYTE")
|
|
|
+ return typeof(Byte);
|
|
|
+ if (typename.ToUpper() == "WORD")
|
|
|
+ return typeof(UInt16);
|
|
|
+ if (typename.ToUpper() == "DWORD")
|
|
|
+ return typeof(UInt32);
|
|
|
+ if (typename.ToUpper() == "INT")
|
|
|
+ return typeof(Int16);
|
|
|
+ if (typename.ToUpper() == "DINT")
|
|
|
+ return typeof(Int32);
|
|
|
+ if (typename.ToUpper() == "REAL")
|
|
|
+ return typeof(float);
|
|
|
+ if (typename.ToUpper() == "LREAL")
|
|
|
+ return typeof(Double);
|
|
|
+ return typeof(bool);
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool LoadPointList()
|
|
|
+ {
|
|
|
+ string filePath = GetConfiguration("点表文件");
|
|
|
+ pointList.Clear();
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string line;
|
|
|
+ string[] arrItem;
|
|
|
+ PlcPoint plcPoint = new PlcPoint() { name = "", address = "", type = null };
|
|
|
+ // 创建一个 StreamReader 的实例来读取文件 ,using 语句也能关闭 StreamReader
|
|
|
+ using (System.IO.StreamReader sr = new System.IO.StreamReader(filePath, Encoding.GetEncoding("GB2312")))
|
|
|
+ {
|
|
|
+ // 从文件读取并显示行,直到文件的末尾
|
|
|
+ while ((line = sr.ReadLine()) != null)
|
|
|
+ {
|
|
|
+ arrItem = line.Split(',');
|
|
|
+ if (arrItem.Length != 3)
|
|
|
+ continue;
|
|
|
+ plcPoint.name = arrItem[0];
|
|
|
+ if (!runInDebug || plcPoint.type == null)
|
|
|
+ {
|
|
|
+ plcPoint.address = arrItem[1];
|
|
|
+ plcPoint.type = GetTypeByName(arrItem[2]);
|
|
|
+ }
|
|
|
+ pointList.Add(plcPoint);
|
|
|
+ textNotice.Text = "已从" + filePath + "读取" + pointList.Count.ToString() + "条数据定义";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ textNotice.Text = "读取数据点表文件(" + filePath + ")发生错误:" + ex.Message;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void timer2_Tick(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ if (!adsClient.IsConnected || startSignal == 0)
|
|
|
+ {
|
|
|
+ BeginConnect();
|
|
|
+ }
|
|
|
+ else if (isRecording)
|
|
|
+ {
|
|
|
+ stopWatch++;
|
|
|
+ if (this.InvokeRequired)
|
|
|
+ this.BeginInvoke((Action)delegate
|
|
|
+ {
|
|
|
+ lableTime.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", stopWatch / 3600, stopWatch / 60, stopWatch % 60);
|
|
|
+ });
|
|
|
+ else
|
|
|
+ lableTime.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", stopWatch / 3600, stopWatch / 60, stopWatch % 60);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (lableTime.Text == "")
|
|
|
+ lableTime.Text = "00:00:00";
|
|
|
+ else
|
|
|
+ lableTime.Text = "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void timer1_Tick(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (adsClient.IsConnected)
|
|
|
+ {
|
|
|
+ if (isManuel)
|
|
|
+ {
|
|
|
+ ReadAllValues();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ bool isStart = (bool)adsClient.ReadAny(startSignal, typeof(bool));
|
|
|
+ if (!isRecording)
|
|
|
+ {
|
|
|
+ if (isStart)
|
|
|
+ StartRecording();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (!isStart)
|
|
|
+ StopRecording();
|
|
|
+ else
|
|
|
+ ReadAllValues();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ textNotice.Text = "数据读取定时器发生错误:" + ex.Message;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getHandle(string varName)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ int handle = adsClient.CreateVariableHandle(varName);
|
|
|
+ return handle;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ textNotice.Text = "获取PLC变量(" + varName + ")发生错误:" + ex.Message;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void BeginConnect()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ adsClient.Connect(plcAdress[0], Convert.ToInt32(plcAdress[1]));
|
|
|
+ startSignal = getHandle(System.Configuration.ConfigurationManager.AppSettings["启动信号"]);
|
|
|
+ if (startSignal == 0)
|
|
|
+ return;
|
|
|
+ for (int i = 0; i < pointList.Count; i++)
|
|
|
+ {
|
|
|
+ handleList.Add(getHandle(pointList[i].address));
|
|
|
+ }
|
|
|
+ button1.Enabled = true;
|
|
|
+ timer1.Enabled = true;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ textNotice.Text = "连接PLC发生发生错误:" + ex.Message;
|
|
|
+ timer1.Enabled = false;
|
|
|
+ button1.Enabled = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void StartRecording()
|
|
|
+ {
|
|
|
+ if (!CreateLogFile())
|
|
|
+ return;
|
|
|
+ isRecording = true;
|
|
|
+ stopWatch = 0;
|
|
|
+ button1.Text = "正在记录";
|
|
|
+ textNotice.Text = "已创建记录文件:" + filePath;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void StopRecording()
|
|
|
+ {
|
|
|
+ fileWriter.Flush();
|
|
|
+ fileWriter.Close();
|
|
|
+ isRecording = false;
|
|
|
+ button1.Text = "开始记录";
|
|
|
+ textNotice.Text = "已保存到记录文件:" + filePath;
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool CreateLogFile()
|
|
|
+ {
|
|
|
+ filePath = filePrefix + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".csv";
|
|
|
+ 当前行数 = 0;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ fileWriter = new StreamWriter(filePath, false, Encoding.GetEncoding("GB2312"));
|
|
|
+ fileWriter.Write("时间");
|
|
|
+ for (int i = 0; i < pointList.Count; i++)
|
|
|
+ {
|
|
|
+ fileWriter.Write("," + pointList[i].name);
|
|
|
+ }
|
|
|
+ fileWriter.WriteLine();
|
|
|
+ fileWriter.Flush();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ textNotice.Text = "创建记录文件(" + filePath + ")发生错误:" + ex.Message;
|
|
|
+ timer1.Enabled = false;
|
|
|
+ button1.Enabled = false;
|
|
|
+ timer2.Enabled = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public delegate void AsyncEventHandler();
|
|
|
+
|
|
|
+ private string getValue(int index)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (handleList[index] == 0)
|
|
|
+ return "";
|
|
|
+ string value = adsClient.ReadAny(handleList[index], pointList[index].type).ToString();
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ textNotice.Text = "读取PLC变量(" + pointList[index].name + ")值时发生错误:" + ex.Message;
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void BeginReadAllValues()
|
|
|
+ {
|
|
|
+ AsyncEventHandler asy = new AsyncEventHandler(AsyncReadAllValues);
|
|
|
+ IAsyncResult result = asy.BeginInvoke(null, asy);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void AsyncReadAllValues()
|
|
|
+ {
|
|
|
+ StringBuilder line = new StringBuilder();
|
|
|
+ line.Append(DateTime.Now.ToString("HH:mm:ss:fff"));
|
|
|
+ for (int i = 0; i < handleList.Count; i++)
|
|
|
+ {
|
|
|
+ string value = getValue(i);
|
|
|
+ int p = value.IndexOf('.');
|
|
|
+ if (p > 0)
|
|
|
+ line.Append("," + value.Substring(0, p + 1 + 小数位数));
|
|
|
+ else
|
|
|
+ line.Append("," + value);
|
|
|
+ }
|
|
|
+ fileWriter.WriteLine(line);
|
|
|
+ 当前行数++;
|
|
|
+ if (单文件行数 > 0 && 当前行数 >= 单文件行数)
|
|
|
+ {
|
|
|
+ fileWriter.Flush();
|
|
|
+ fileWriter.Close();
|
|
|
+ CreateLogFile();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ReadAllValues()
|
|
|
+ {
|
|
|
+ BeginReadAllValues();
|
|
|
+ //string time = DateTime.Now.ToString("HH:mm:ss.fff");
|
|
|
+ //fileWriter.Write(time);
|
|
|
+ //for (int i = 0; i < handleList.Count; i++)
|
|
|
+ //{
|
|
|
+ // string value = adsClient.ReadAny(handleList[i], pointList[i].type).ToString();
|
|
|
+ // fileWriter.Write("," + value);
|
|
|
+ //}
|
|
|
+ //fileWriter.WriteLine();
|
|
|
+ //fileWriter.Flush();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void button1_Click(object sender, EventArgs e)
|
|
|
+ {
|
|
|
+ if (isRecording)
|
|
|
+ {
|
|
|
+ StopRecording();
|
|
|
+ isManuel = true;
|
|
|
+ timer1.Enabled = false;
|
|
|
+ timer2.Enabled = false;
|
|
|
+ button1.Text = "已停止";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (isManuel)
|
|
|
+ {
|
|
|
+ isManuel = false;
|
|
|
+ timer1.Enabled = true;
|
|
|
+ timer2.Enabled = true;
|
|
|
+ button1.Text = "开始记录";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ isManuel = true;
|
|
|
+ StartRecording();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|