|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using Mesnac.Equips;
|
|
|
|
|
|
namespace Mesnac.Equip.OMRON.HostLink.COM
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 三菱通讯封装设备类
|
|
|
/// </summary>
|
|
|
public class Equip : BaseEquip
|
|
|
{
|
|
|
private SerialPortFactory _serialPortFactory = null; //SerialPortFactory.GetInstance("00", "COM3", 9600, "Even", 7, "2", 1024);
|
|
|
private bool _isOpen = false; //是否打开连接
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取串口工厂
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
private SerialPortFactory GetSerialPortFactory()
|
|
|
{
|
|
|
Mesnac.Equips.Connection.COM.ConnType connType = (Mesnac.Equips.Connection.COM.ConnType)this.Main.ConnType;
|
|
|
string stationNum = connType.StationNum;
|
|
|
string portName = connType.PortName;
|
|
|
int baudRate = connType.BaudRate;
|
|
|
string parity = connType.Parity;
|
|
|
int dataBits = connType.DataBits;
|
|
|
string stopBits = connType.StopBits;
|
|
|
int buffSize = connType.BuffSize;
|
|
|
this._serialPortFactory = SerialPortFactory.GetInstance(stationNum, portName, baudRate, parity, dataBits, stopBits, buffSize);
|
|
|
return this._serialPortFactory;
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 打开PLC设备
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
public override bool Open()
|
|
|
{
|
|
|
lock (this)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
if (this._isOpen == true || (_serialPortFactory != null && _serialPortFactory.MainSerialPort.IsOpen))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
this.State = false;
|
|
|
this._serialPortFactory = this.GetSerialPortFactory();
|
|
|
this._serialPortFactory.MainSerialPort.Open();
|
|
|
|
|
|
if (!_serialPortFactory.MainSerialPort.IsOpen)
|
|
|
{
|
|
|
ICSharpCode.Core.LoggingService.Warn("PLC连接失败:串口未打开失败!");
|
|
|
this.State = false;
|
|
|
return this.State;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
this.State = true;
|
|
|
this._isOpen = true;
|
|
|
//Console.WriteLine("连接成功!");
|
|
|
return this.State;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
this.State = false;
|
|
|
this._isOpen = false;
|
|
|
Console.WriteLine(ex.Message);
|
|
|
return this.State;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// PLC数据读取方法
|
|
|
/// </summary>
|
|
|
/// <param name="block">要读取的块号</param>
|
|
|
/// <param name="start">要读取的起始字</param>
|
|
|
/// <param name="len">要读取的长度,最大255,超过255则不读取</param>
|
|
|
/// <param name="buff"></param>
|
|
|
/// <returns></returns>
|
|
|
public override bool Read(string block, int start, int len, out object[] buff)
|
|
|
{
|
|
|
lock (this)
|
|
|
{
|
|
|
buff = new object[len];
|
|
|
try
|
|
|
{
|
|
|
if (len > 256)
|
|
|
{
|
|
|
for (int i = 0; i < len; i++)
|
|
|
{
|
|
|
buff[i] = 0;
|
|
|
}
|
|
|
base.State = false;
|
|
|
return false;
|
|
|
}
|
|
|
int maxOneLen = 20; //单次允许读取的最大长度,欧姆龙限制为20个字
|
|
|
int count = len / maxOneLen; //要读取的次数
|
|
|
int mod = len % maxOneLen; //剩余的长度
|
|
|
bool flag = true; //保存读取标志
|
|
|
for (int i = 0; i < count; i++)
|
|
|
{
|
|
|
object[] _buff = new object[maxOneLen];
|
|
|
flag = this.ReadByLen(block, start + i * maxOneLen, maxOneLen, out _buff);
|
|
|
if (flag == false)
|
|
|
{
|
|
|
base.State = flag;
|
|
|
return false;
|
|
|
}
|
|
|
for (int k = i * maxOneLen; k < (i + 1) * maxOneLen; k++)
|
|
|
{
|
|
|
buff[k] = _buff[k - i * maxOneLen];
|
|
|
}
|
|
|
}
|
|
|
if (mod > 0)
|
|
|
{
|
|
|
object[] _buff = new object[mod];
|
|
|
flag = this.ReadByLen(block, start + count * maxOneLen, mod, out _buff);
|
|
|
if (flag == false)
|
|
|
{
|
|
|
base.State = flag;
|
|
|
return false;
|
|
|
}
|
|
|
for (int k = count * maxOneLen; k < count * maxOneLen + mod; k++)
|
|
|
{
|
|
|
buff[k] = _buff[k - count * maxOneLen];
|
|
|
}
|
|
|
}
|
|
|
base.State = flag;
|
|
|
return flag;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
ICSharpCode.Core.LoggingService.Error(String.Format("读取PLC(OMRON)设备失败-({0})!", ex.Message));
|
|
|
base.State = false;
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 单次读取最长20个字的方法
|
|
|
/// </summary>
|
|
|
/// <param name="block">块号</param>
|
|
|
/// <param name="start">起始字</param>
|
|
|
/// <param name="len">长度,最长不超过100</param>
|
|
|
/// <param name="buff">数据缓冲区,存放读取的数据</param>
|
|
|
/// <returns>读取成功返回true,读取失败返回false</returns>
|
|
|
private bool ReadByLen(string block, int start, int len, out object[] buff)
|
|
|
{
|
|
|
lock (this)
|
|
|
{
|
|
|
buff = new object[len];
|
|
|
if (!this.Open())
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
int state = len;
|
|
|
int[] _buff = new int[len];
|
|
|
int iblock = Convert.ToInt32(block);
|
|
|
//iblock = iblock + start;
|
|
|
string result = this._serialPortFactory.Read(iblock, start, len, out _buff);
|
|
|
if (result != "00")
|
|
|
{
|
|
|
ICSharpCode.Core.LoggingService.Warn("PLC读取失败:" + this.GetErrInfo(result));
|
|
|
this.State = false;
|
|
|
return false;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
this.State = true;
|
|
|
}
|
|
|
int iReadLen = len;
|
|
|
if (iReadLen > state)
|
|
|
{
|
|
|
iReadLen = state;
|
|
|
}
|
|
|
for (int i = 0; i < iReadLen; i++)
|
|
|
{
|
|
|
int value = _buff[i];
|
|
|
if (value > ushort.MaxValue)
|
|
|
{
|
|
|
value = ushort.MaxValue - value;
|
|
|
}
|
|
|
buff[i] = value;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private ushort ToValue(object obj, ushort defaultValue)
|
|
|
{
|
|
|
ushort result = 0;
|
|
|
if (obj != null
|
|
|
&& obj != DBNull.Value
|
|
|
&& ushort.TryParse(obj.ToString(), out result))
|
|
|
{
|
|
|
return result;
|
|
|
}
|
|
|
return defaultValue;
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// PLC数据写入方法
|
|
|
/// </summary>
|
|
|
/// <param name="block">要写入的块号</param>
|
|
|
/// <param name="start">起始字</param>
|
|
|
/// <param name="buff">要写入PLC的数据</param>
|
|
|
/// <returns>写入成功返回true,失败返回false</returns>
|
|
|
public override bool Write(int block, int start, object[] buff)
|
|
|
{
|
|
|
lock (this)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
if (buff.Length > 256)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
int len = buff.Length;
|
|
|
int maxOneLen = 25; //单次允许读取的最大长度,OMRON限制为25个字
|
|
|
int count = len / maxOneLen; //要读取的次数
|
|
|
int mod = len % maxOneLen; //剩余的长度
|
|
|
bool flag = true; //保存写入标志
|
|
|
for (int i = 0; i < count; i++)
|
|
|
{
|
|
|
object[] _buff = new object[maxOneLen];
|
|
|
for (int k = i * maxOneLen; k < (i + 1) * maxOneLen; k++)
|
|
|
{
|
|
|
_buff[k - i * maxOneLen] = buff[k];
|
|
|
}
|
|
|
flag = this.WriteMax25(block, start + i * maxOneLen, _buff);
|
|
|
if (flag == false)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
if (mod > 0)
|
|
|
{
|
|
|
object[] _buff = new object[mod];
|
|
|
for (int k = count * maxOneLen; k < count * maxOneLen + mod; k++)
|
|
|
{
|
|
|
_buff[k - count * maxOneLen] = buff[k];
|
|
|
}
|
|
|
flag = this.WriteMax25(block, start + count * maxOneLen, _buff);
|
|
|
|
|
|
}
|
|
|
return flag;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
ICSharpCode.Core.LoggingService.Error(String.Format("写入PLC(OMRON)设备失败-({0})!", ex.Message));
|
|
|
//Console.WriteLine(ex.Message);
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 单次写入最多25个字至PLC
|
|
|
/// </summary>
|
|
|
/// <param name="block">要写入的块号</param>
|
|
|
/// <param name="start">要写入的起始字</param>
|
|
|
/// <param name="buff">要写入的数据</param>
|
|
|
/// <returns>写入成功返回true,失败返回false</returns>
|
|
|
private bool WriteMax25(int block, int start, object[] buff)
|
|
|
{
|
|
|
lock (this)
|
|
|
{
|
|
|
if (!this.Open())
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
int state = buff.Length;
|
|
|
int[] _buff = new int[buff.Length];
|
|
|
for (int i = 0; i < buff.Length; i++)
|
|
|
{
|
|
|
int value = 0;
|
|
|
int.TryParse(buff[i].ToString(), out value);
|
|
|
_buff[i] = value;
|
|
|
}
|
|
|
string result = this._serialPortFactory.Write(block, start, _buff);
|
|
|
if (result != "00")
|
|
|
{
|
|
|
ICSharpCode.Core.LoggingService.Error("PLC【欧姆龙】写入失败:" + this.GetErrInfo(result));
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 关闭PLC设备
|
|
|
/// </summary>
|
|
|
public override void Close()
|
|
|
{
|
|
|
lock (this)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
this._serialPortFactory.MainSerialPort.Close();
|
|
|
|
|
|
if (this._serialPortFactory.MainSerialPort.IsOpen)
|
|
|
{
|
|
|
ICSharpCode.Core.LoggingService.Warn("PLC【欧姆龙】关闭失败:端口处于打开状态");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
this.State = false;
|
|
|
this._isOpen = false;
|
|
|
//Console.WriteLine("关闭成功!");
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
ICSharpCode.Core.LoggingService.Error("PLC【欧姆龙】关闭失败:" + ex.Message);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#region 根据错误代码返回错误信息
|
|
|
/// <summary>根据错误代码返回错误信息
|
|
|
/// </summary>
|
|
|
/// <param name="errCode">错误码</param>
|
|
|
/// <returns>错误信息</returns>
|
|
|
public string GetErrInfo(string errCode)
|
|
|
{
|
|
|
string result = "未知错误";
|
|
|
switch (errCode)
|
|
|
{
|
|
|
case "00":
|
|
|
result = "正常完成!";
|
|
|
break;
|
|
|
case "01":
|
|
|
result = "在RUN模式下不可执行!";
|
|
|
break;
|
|
|
case "02":
|
|
|
result = "在MONITOR模式下不可执行";
|
|
|
break;
|
|
|
case "04":
|
|
|
result = "地址越界";
|
|
|
break;
|
|
|
case "0B":
|
|
|
result = "在PROGRAM模式下不可执行";
|
|
|
break;
|
|
|
case "13":
|
|
|
result = "FCS错误";
|
|
|
break;
|
|
|
case "14":
|
|
|
result = "格式错误";
|
|
|
break;
|
|
|
case "15":
|
|
|
result = "入口号数据错误";
|
|
|
break;
|
|
|
case "16":
|
|
|
result = "命令不支持";
|
|
|
break;
|
|
|
case "18":
|
|
|
result = "帧长度错误";
|
|
|
break;
|
|
|
case "19":
|
|
|
result = "不可执行";
|
|
|
break;
|
|
|
case "23":
|
|
|
result = "用户存储区写保护";
|
|
|
break;
|
|
|
case "A3":
|
|
|
result = "由于数据传送中FCS错误而终止";
|
|
|
break;
|
|
|
case "A4":
|
|
|
result = "由于数据传送中格式错误而终止";
|
|
|
break;
|
|
|
case "A5":
|
|
|
result = "由于数据传送中入口号数据错误而终止";
|
|
|
break;
|
|
|
case "A8":
|
|
|
result = "由于数据传送中帧长错误而终止";
|
|
|
break;
|
|
|
default:
|
|
|
result = "未知错误";
|
|
|
break;
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
#endregion
|
|
|
}
|
|
|
} |