Files
ENIG/Cs_HMI/TestProject/Test_ProPLC/Form1.cs
2025-01-07 16:08:02 +09:00

660 lines
22 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Test_ProPLC
{
public partial class Form1 : Form
{
arDev.FakePLC dev2;
public Form1()
{
InitializeComponent();
this.serialPort1.DataReceived += SerialPort1_DataReceived;
dev2 = new arDev.FakePLC();
this.dev2.ValueChanged += Dev2_ValueChanged;
this.dev2.Message += Dev2_Message;
this.FormClosed += Form1_FormClosed;
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
timer1.Stop();
}
private void Dev2_ValueChanged(object sender, arDev.Arduino.DIO.IOValueEventArgs e)
{
addMsg2($"val({e.ArrIDX}) -> {e.NewValue}");
}
byte[] buffer1;
List<byte> Tempbuffer1 = new List<byte>();
byte[] buffer2;
List<byte> Tempbuffer2 = new List<byte>();
Boolean STX11 = false;
Boolean STX21 = false;
Boolean ETX11 = false;
Boolean STX12 = false;
Boolean STX22 = false;
Boolean ETX12 = false;
//MAIN PLC
byte[] DIpinList1 = new byte[] { 22, 23, 24, 25, 26, 27, 28, 29, 41 };
string[] DIpinName1 = new string[] { "EMERGENCTY", "OVR_L", "LIDAR_STOP", "LIDAR_SLOW", "OVR_R", "MARK", "GATEOUT_B", "GATEOUT_F", "ALIGN" };
byte[] DOpinList1 = new byte[] { 33, 34, 35, 36, 37, 43, 44, 39, 40 };
string[] DopinName1 = new string[] { "MOT_POWER_GUIDE", "MOT_POWER_L", "MOT_POWER_R", "LIDAR_DIR", "CHARGE_ON", "MOT_DIR_L", "MOT_RUN_L", "MOT_DIR_R", "MOT_RUN_R" };
// SUB PLC
byte[] DIpinList2 = new byte[] { 22, 23, 24, 25, 41, 42, 43, 45, 38 };
string[] DIpinName2 = new string[] { "BTN_GUIDE_UP", "BTN_GUIDE_DN", "BTN_QA1", "BTN_QC", "LIM_HIGH_R", "LIM_LOW_R", "LIM_HIGH_L", "BTN_PACK", "LIM_LOW_L" };
byte[] DOpinList2 = new byte[] { 30, 31, 32, 33 };
string[] DopinName2 = new string[] { "GMOT_INT", "GMOT_DIR", "GMOT_RUN", "GMOT_STA" };
byte LEN1 = 0;
byte CHK1 = 0;
int bufferCount1 = 0;
byte LEN2 = 0;
byte CHK2 = 0;
int bufferCount2 = 0;
private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
bufferCount1 = this.serialPort1.BytesToRead;
byte[] rxBuffer = new byte[bufferCount1];
serialPort1.Read(rxBuffer, 0, bufferCount1);
foreach (byte incomingByte in rxBuffer)
{
if (STX11 == false)
{
if (incomingByte != '@')
{
STX21 = false;
ETX11 = false;
continue;
}
else
{
STX11 = true;
Tempbuffer1.Add(incomingByte);
}
}
else if (STX21 == false)
{
if (Tempbuffer1.Count != 1 || Tempbuffer1.Count < 1 || Tempbuffer1[0] != '@' || incomingByte != '@')
{
STX11 = false;
ETX11 = false;
continue;
}
else
{
STX21 = true;
Tempbuffer1.Add(incomingByte);
}
}
else
{
Tempbuffer1.Add(incomingByte);
//여기서부터는무조건 누적한다.
if (Tempbuffer1.Count == 3)
{
if (Tempbuffer1[0] != 0x40 || Tempbuffer1[1] != '@')
{
STX11 = false;
STX21 = false;
ETX11 = false;
LEN1 = 0;
Tempbuffer1.Clear();
}
else LEN1 = incomingByte; //데이터 길이가온다
}
else if (Tempbuffer1.Count == LEN1 + 2 + 1 + 1) //체크섬이 왔다
{
CHK1 = incomingByte;
}
else if (Tempbuffer1.Count == LEN1 + 2 + 1 + 1 + 1) //ETX1
{
if (incomingByte != 0x0D)
{
//ETX가 와야하는데 다른데이터가 왔다
STX11 = false;
STX21 = false;
ETX11 = false;
Console.WriteLine("에러 모두 파기");
Tempbuffer1.Clear();
}
}
else if (Tempbuffer1.Count == LEN1 + 2 + 1 + 1 + 1 + 1)
{
//전체길이를 만족햇다.
if (incomingByte != 0x0A)
{
//ETX가 와야하는데 다른데이터가 왔다
STX11 = false;
STX21 = false;
ETX11 = false;
Console.WriteLine("에러 모두 파기");
Tempbuffer1.Clear();
}
else
{
STX11 = false;
STX21 = false;
ETX11 = false;
if (buffer1 == null) buffer1 = new byte[Tempbuffer1.Count];
else if (buffer1.Length != Tempbuffer1.Count) Array.Resize(ref buffer1, Tempbuffer1.Count);
Tempbuffer1.CopyTo(buffer1);
Tempbuffer1.Clear();
parser(buffer1, tbMsg1, 0);
}
}
}
}
}
private void Dev2_Message(object sender, arDev.arRS232.MessageEventArgs e)
{
addMsg2($"{e.Message}");
}
delegate void DisplayMessage(string message);
void parser(byte[] buffer, Action<string> func, int type)
{
// DisplayMessage messageTarget;
var hexString = buffer.GetHexString();
var len = buffer[2];
if (len + 6 != buffer.Length)
{
func(string.Format("길이오류 예상:{0},수신:{1},{2}", len + 5, buffer.Length, hexString));
}
else if (buffer[0] != 0x40 || buffer[1] != 0x40 || buffer[buffer.Length - 2] != 0x0D || buffer[buffer.Length - 1] != 0x0A)
{
func(string.Format("헤더 오류 : {0}", hexString));
}
else
{
var cmd = buffer[3];
if (cmd == 'I') //IOData
{
if (len != 15)
{
func("IO수신길이오류:" + DateTime.Now.ToString("mm:ss.fff") + " 수신 : " + hexString);
}
else
{
var IOData = BitConverter.ToUInt32(buffer, 4);
var An1 = BitConverter.ToUInt16(buffer, 8);
var An2 = BitConverter.ToUInt16(buffer, 10);
var Ao11 = buffer[12];
var Ao12 = buffer[13];
var FGData = BitConverter.ToInt32(buffer, 14);
byte[] buf_iodata = new byte[4];
Array.Copy(buffer, 4, buf_iodata, 0, 4);
var ba = new System.Collections.BitArray(buf_iodata);
for (int i = 0; i < 32; i++)
{
Boolean val = ba[i];
if (val)
{
}
if (type == 0) this.gv1.setValue(i, val);
else this.gv2.setValue(i, val);
}
var binstr = Convert.ToString(IOData, 2).PadLeft(32, '0');
string msg = string.Format(DateTime.Now.ToString("mm:ss.fff") + " IO:{0},AN={1:0000},{2:0000},FG={3},AO={4},{5}",
binstr, An1, An2, FGData, Ao11, Ao12);
func(msg);
if (type == 0) gv1.Invalidate();
else gv2.Invalidate();
}
}
else if (cmd == 'T')
{
Boolean errorMessage = buffer[4] == 1;
var message = System.Text.Encoding.Default.GetString(buffer, 5, len - 2);//데이터타입과 에러여부 제거
if (type == 0)
addMsg1("Rx : " + hexString + ", 메세지: " + message);
else
addMsg2("Rx : " + hexString + ", 메세지: " + message);
}
else
{
if (type == 0)
addMsg1(DateTime.Now.ToString("mm:ss.fff") + " 수신 : " + hexString + "\n" + "Data=" + System.Text.Encoding.Default.GetString(buffer));
else
addMsg2(DateTime.Now.ToString("mm:ss.fff") + " 수신 : " + hexString + "\n" + "Data=" + System.Text.Encoding.Default.GetString(buffer));
//func();
}
}
//Console.WriteLine("Rx : " + hexString);
}
void tbMsg1(string m)
{
if (textBox3.InvokeRequired)
{
textBox3.BeginInvoke(new Action(() =>
{
textBox3.Text = (m + "\n");
// textBox3.ScrollToCaret();
}));
}
else
{
textBox3.Text = (m + "\n");
//textBox3.ScrollToCaret();
}
}
void tbMsg2(string m)
{
if (textBox4.InvokeRequired)
{
textBox4.BeginInvoke(new Action(() =>
{
textBox4.Text = (m + "\n");
// richTextBox2.ScrollToCaret();
}));
}
else
{
textBox4.Text = (m + "\n");
//richTextBox2.ScrollToCaret();
}
}
private void button1_Click(object sender, EventArgs e)
{
if (this.dev2.IsOpen)
{
this.serialPort1.Close();
this.button1.BackColor = SystemColors.Control;
}
else
{
if (textbox1.Text.isEmpty()) return;
this.serialPort1.PortName = textbox1.Text;
this.serialPort1.BaudRate = 250000;
this.serialPort1.Open();
button1.BackColor = Color.Lime;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
this.Text = bufferCount1.ToString() + "/" + bufferCount2.ToString();
}
private void button2_Click(object sender, EventArgs e)
{
if (textbox2.Text.isEmpty()) return;
if (this.dev2.IsOpen)
{
this.dev2.Close();
this.button2.BackColor = SystemColors.Control;
}
else
{
this.dev2.PortName = textbox2.Text;
this.dev2.BaudRate = int.Parse(comboBox1.Text);
this.dev2.Open();
button2.BackColor = Color.Lime;
// timer1.Start();
}
addMsg2($"open:{this.dev2.IsOpen}");
}
private void Form1_Load(object sender, EventArgs e)
{
textbox1.Items.Clear();
textbox2.Items.Clear();
foreach (var port in System.IO.Ports.SerialPort.GetPortNames())
{
textbox1.Items.Add(port);
textbox2.Items.Add(port);
}
// textbox1.Text = "COM15";
// textbox2.Text = "COM16";
List<Boolean> values = new List<bool>();
for (int i = 0; i < 32; i++)
values.Add(false);
this.gv1.setValue(values.ToArray());
this.gv2.setValue(values.ToArray());
//그리드뷰 값초기화
for (int i = 0; i < 32; i++)
{
string pinName = i.ToString();
if (i < 16 && i < DIpinName1.Length)
pinName = string.Format("[{0}:{2}] {1}", i, DIpinName1[i], DIpinList1[i]);
else if (i >= 16 && (i - 16) < DopinName1.Length)
pinName = string.Format("[{0}:{2}] {1}", i, DopinName1[i - 16], DOpinList1[i - 16]);
this.gv1.setTitle(i, pinName);
this.gv1.setValue(i, 0);
}
for (int i = 0; i < 32; i++)
{
string pinName = i.ToString();
if (i < 16)
{
var pin = (arDev.FakePLC.DIName)i;
pinName = $"[{i}] {pin}";
}
else
{
var pin = (arDev.FakePLC.DOName)(i-16);
pinName = $"[{i}] {pin}";
}
this.gv2.setTitle(i, pinName);
this.gv2.setValue(i, 0);
}
timer1.Start();
}
private void gv1_ItemClick(object sender, arFrame.Control.GridView.ItemClickEventArgs e)
{
//sub item click
if (e.idx < 16)
{
Util.MsgE("입력은 상태를 변경할 수 없습니다");
}
else
{
//이 인덱스에 해당하는 포트번호를 가져왕야함
var dataIndex = e.idx - 16;
if (dataIndex >= 0)
{
var pinNo = DOpinList1[e.idx - 16];
var curVal = gv1.getValue(e.idx);
byte newval = (byte)(curVal == 0 ? 1 : 0);
Sendcommand1(eCommand1.SET_DOUTPUT, pinNo, newval);
}
else Util.MsgE("해당 주소는 허용되지 않습니다.");
}
}
byte makeChecksum(byte[] buffer)
{
//return 0;
byte chk = 0;
foreach (var b in buffer)
chk = (byte)(chk ^ b);
return chk;
}
enum eCommand1 : byte
{
LOAD = 0, //EEPROM 불러오기
SAVE, //EEPROM 저장
RESET, //초기화
SET_PINMODE, //PINMODE 설정
SET_DOUTPUT, //디지털출력설정(포트번호,값[1,0])
SET_AOUTPUT, //아날로그출력설정(포트GET_SETTING = 50, 포트번호,값(0~255)
GET_SETTING = 50, //셋팅값 요청
MOT = 100, //p1(0=left,1=right), p2(0=stop,1=pos run,2=neg run)
MOVE_GO,
MOVE_BACK,
MOVE_LEFT,
MOVE_RIGHT,
MOVE_STOP
}
enum eCommand2 : byte
{
LOAD = 0, //EEPROM 불러오기
SAVE, //EEPROM 저장
RESET, //초기화
SET_PINMODE, //PINMODE 설정
SET_DOUTPUT, //디지털출력설정(포트번호,값[1,0])
SET_AOUTPUT, //아날로그출력설정(포트번호,값[0~255])
GET_SETTING = 50, //셋팅값 요청
GUIDE_MOT,
SET_GUIDE_SPD = 100,//가이드커버(양쪽) 속도 설정(0~255)
}
void addMsg1(string m)
{
if (logMain.InvokeRequired)
{
logMain.BeginInvoke(new Action(() =>
{
if (m.IndexOf('\n') != -1) m = m.Replace("\r", "").Replace("\n", "");
logMain.AddMsg(m);
}));
}
else
{
if (m.IndexOf('\n') != -1) m = m.Replace("\r", "").Replace("\n", "");
logMain.AddMsg(m);
}
}
void addMsg2(string m)
{
if (logSub.InvokeRequired)
{
logSub.BeginInvoke(new Action(() =>
{
if (m.IndexOf('\n') != -1) m = m.Replace("\r", "").Replace("\n", "");
logSub.AddMsg(m);
}));
}
else
{
if (m.IndexOf('\n') != -1) m = m.Replace("\r", "").Replace("\n", "");
logSub.AddMsg(m);
}
}
private void gv2_ItemClick(object sender, arFrame.Control.GridView.ItemClickEventArgs e)
{
//sub item click
if (e.idx < 16)
{
Util.MsgE("입력은 상태를 변경할 수 없습니다");
}
else
{
//이 인덱스에 해당하는 포트번호를 가져왕야함
var dataIndex = e.idx - 16;
if (dataIndex >= 0)
{
var pinNo = DOpinList2[e.idx - 16];
var curVal = gv2.getValue(e.idx);
byte newval = (byte)(curVal == 0 ? 1 : 0);
// Sendcommand2(eCommand2.SET_DOUTPUT, pinNo, newval);
}
else Util.MsgE("해당 주소는 허용되지 않습니다.");
}
}
void Sendcommand1(eCommand1 cmd, byte p1, byte p2)
{
//이번호의 상태를 on/off 해줘야함
List<byte> buffer = new List<byte>();
buffer.Add((byte)cmd); //command
buffer.Add(p1);
buffer.Add(p2);
byte dataLen = (byte)buffer.Count; //데이터길이
byte checksum = makeChecksum(buffer.ToArray());
buffer.Insert(0, (byte)'@'); //stx
buffer.Insert(1, (byte)'@'); //stx
buffer.Insert(2, dataLen);
buffer.Add(checksum); //길이를 제외한 실제 데이터 영역만 체크섬
buffer.Add(0x0D); //etx
buffer.Add(0x0A); //etx
addMsg1("Tx Buffer : " + buffer.ToArray().GetHexString());
if (this.serialPort1.IsOpen)
serialPort1.Write(buffer.ToArray(), 0, buffer.Count);
else
addMsg1("포트(2)가 열리지 않았습니다");
}
private void button3_Click(object sender, EventArgs e)
{
//-zup
dev2.ZMot(arDev.FakePLC.ZMotDirection.Up);
}
private void button4_Click(object sender, EventArgs e)
{
//z-stop
dev2.ZMot(arDev.FakePLC.ZMotDirection.Stop);
}
private void button5_Click(object sender, EventArgs e)
{
//z-down
dev2.ZMot(arDev.FakePLC.ZMotDirection.Down);
}
private void button8_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOT, 0, 1);
}
private void button6_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOT, 0, 0);
}
private void button7_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOT, 0, 2);
}
private void button10_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOT, 1, 2);
}
private void button9_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOT, 1, 0);
}
private void button11_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOT, 1, 1);
}
private void button14_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOVE_GO, 0, 0);
}
private void button12_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOVE_STOP, 0, 0);
}
private void button13_Click(object sender, EventArgs e)
{
Sendcommand1(eCommand1.MOVE_BACK, 0, 0);
}
private void button15_Click(object sender, EventArgs e)
{
//지정된 %의 값을 전송한다
var but = sender as Button;
var percValue = byte.Parse(but.Text.ToString());
var realValue = (percValue / 100.0) * 255.0;
Sendcommand1(eCommand1.SET_AOUTPUT, 11, (byte)realValue);
Sendcommand1(eCommand1.SET_AOUTPUT, 12, (byte)realValue);
}
private void button34_Click(object sender, EventArgs e)
{
//지정된 %의 값을 전송한다
var but = sender as Button;
var percValue = byte.Parse(but.Text.ToString());
var realValue = (percValue / 100.0) * 255.0;
// Sendcommand2(eCommand2.SET_AOUTPUT, 11, (byte)realValue); //Z축 모터는 동일하게 사용한다
}
private void timer1_Tick_1(object sender, EventArgs e)
{
timer1.Stop();
if (dev2 != null && dev2.IsOpen)
{
for(byte i = 0; i < 32;i++)
{
bool v = false;
if (i < 16) v = dev2.GetValueI(i);
else v = dev2.GetValueO((byte)(i-16));
this.gv2.setValue(i, v);
}
this.gv2.Invalidate();
}
timer1.Start();
}
}
}