初始化上传
This commit is contained in:
51
常用工具集/Utility/Network/Omrons/DataTools.cs
Normal file
51
常用工具集/Utility/Network/Omrons/DataTools.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OmronLib
|
||||
{
|
||||
public static class DataTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 将byte类型数据数组转换为16进制字符串形式
|
||||
/// </summary>
|
||||
/// <param name="hex"></param>
|
||||
/// <param name="len"></param>
|
||||
/// <returns></returns>
|
||||
public static string ByteToHexString(byte[] hex, int len)
|
||||
{
|
||||
string returnstr = "";
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
returnstr += hex[i].ToString("X2");
|
||||
}
|
||||
return returnstr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个长字符串转化为每个元素包含两个字符的字符数组
|
||||
/// </summary>
|
||||
/// <param name="src"></param>
|
||||
/// <param name="def"></param>
|
||||
/// <returns></returns>
|
||||
public static string[] StrToStrArray(string src)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] res = new string[src.Length / 2];
|
||||
|
||||
for (int i = 0; i < src.Length / 2; i++)
|
||||
{
|
||||
res[i] = src.Substring(i * 2, 2);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
960
常用工具集/Utility/Network/Omrons/Omron.cs
Normal file
960
常用工具集/Utility/Network/Omrons/Omron.cs
Normal file
@@ -0,0 +1,960 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace OmronLib
|
||||
{
|
||||
/*
|
||||
*Copyright: Copyright (c) 2019
|
||||
*Created on 2019-11-7
|
||||
*Author: coder_li@outlook.com
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 欧姆龙PLC使用FINS通讯,在与PLC建立tcp连接后,必须先进行读写准备,获取到DA1和SA1
|
||||
/// 这里默认读取200个D区地址,从D5000开始到D5199,读取的返回值都是高位在前低位在后
|
||||
/// 写入时都是单个寄存器写入,写入的内容也是高位在前低位在后
|
||||
/// </summary>
|
||||
public class Omron
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// PLCIP
|
||||
/// </summary>
|
||||
public IPAddress IPAddr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PLC端口号
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
public int Timeout = 1000;
|
||||
/// <summary>
|
||||
/// 获取是否已经连接到PLC
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PlcClient == null)
|
||||
return false;
|
||||
else
|
||||
return PlcClient.Connected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PLC内存区域类型
|
||||
/// </summary>
|
||||
public enum AreaType
|
||||
{
|
||||
CIO_Bit = 0x30,
|
||||
WR_Bit = 0x31,
|
||||
HR_Bit = 0x32,
|
||||
AR_Bit = 0x33,
|
||||
DM_Bit = 0x02,
|
||||
CIO_Word = 0xB0,
|
||||
WR_Word = 0xB1,
|
||||
HR_Word = 0xB2,
|
||||
AR_Word = 0xB3,
|
||||
DM_Word = 0x82
|
||||
}
|
||||
|
||||
|
||||
private readonly object locker = new object();
|
||||
private TcpClient PlcClient = null;
|
||||
private NetworkStream Stream = null;
|
||||
private IPEndPoint PlcIP = null;
|
||||
|
||||
private byte DA1 = 0x00, SA1 = 0x00;
|
||||
|
||||
public Omron()
|
||||
{ }
|
||||
|
||||
#region 命令模板
|
||||
/// <summary>
|
||||
/// 写命令
|
||||
/// </summary>
|
||||
private readonly byte[] WriteCommand = new byte[] { 0x46, 0x49, 0x4e, 0x53, // F I N S
|
||||
0x00, 0x00, 0x00, 0x1c, // 命令长度
|
||||
0x00, 0x00, 0x00, 0x02, // 命令码
|
||||
0x00, 0x00, 0x00, 0x00, // 错误码
|
||||
0x80, 0x00, 0x02, 0x00, // ICF RSV GCT DNA
|
||||
0x00, 0x00, 0x00, 0x00, // DA1 DA2 SNA SA1
|
||||
0x00, 0xDA, // SA2 SID
|
||||
0x01, 0x02, // FINS主命令 FINS从命令 (01 02 写)
|
||||
0x82, 0x00, 0x00, 0x00, // 寄存器控制位 开始字地址(从高到低) 开始位地址
|
||||
0x00, 0x01 }; // 写入数量(从高到低) 后面都是写入的内容(可以加长)
|
||||
/// <summary>
|
||||
/// 读命令
|
||||
/// </summary>
|
||||
private readonly byte[] ReadCommand = new byte[] { 0x46, 0x49, 0x4e, 0x53, // F I N S
|
||||
0x00, 0x00, 0x00, 0x1a, // 命令长度
|
||||
0x00, 0x00, 0x00, 0x02, // 命令码
|
||||
0x00, 0x00, 0x00, 0x00, // 错误码
|
||||
0x80, 0x00, 0x02, 0x00, // ICF RSV GCT DNA ***************
|
||||
0x00, 0x00, 0x00, 0x00, // DA1 DA2 SNA SA1 FINS Header
|
||||
0x00, 0xDA, // SA2 SID ***************
|
||||
0x01, 0x01, // FINS主命令 FINS从命令 (01 01 读) ***************
|
||||
0x82, 0x00, 0x00, 0x00, // 寄存器控制位 开始字地址(高,低) 开始位地址 FINS Command
|
||||
0x00, 0x01 }; // 读取数量(高,低) ***************
|
||||
/// <summary>
|
||||
/// 获取节点地址的命令
|
||||
/// </summary>
|
||||
private readonly byte[] PrepareCmd = new byte[] { 0x46, 0x49, 0x4e, 0x53,
|
||||
0x00, 0x00, 0x00, 0x0c,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 向PLC发送指令
|
||||
/// </summary>
|
||||
/// <param name="commands">指令</param>
|
||||
/// <param name="info">报错信息</param>
|
||||
/// <returns>是否发送成功</returns>
|
||||
private bool DataSend(byte[] commands)
|
||||
{
|
||||
string info;
|
||||
try
|
||||
{
|
||||
if (this.PlcClient != null && PlcClient.Connected)
|
||||
{
|
||||
//lock (locker)
|
||||
{
|
||||
if (Stream == null) Stream = PlcClient.GetStream();
|
||||
Stream.Write(commands, 0, commands.Length);
|
||||
Stream.Flush();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
info = "连接已断开";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
info = "发送指令到PLC失败 " + exp.Message;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从PLC读取数据
|
||||
/// </summary>
|
||||
/// <param name="isExtCmd"></param>
|
||||
/// <param name="info">报错信息</param>
|
||||
/// <returns></returns>
|
||||
private string DataRead()
|
||||
{
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytestoread = 0;
|
||||
string info;
|
||||
|
||||
try
|
||||
{
|
||||
//if (Stream.DataAvailable)
|
||||
{
|
||||
int start = Environment.TickCount;
|
||||
do
|
||||
{
|
||||
bytestoread = Stream.Read(buffer, 0, buffer.Length);
|
||||
if (Math.Abs(Environment.TickCount - start) >= 20000)
|
||||
{
|
||||
info = "PLC应答超时,请确认PLC连接线路及cpu是否有报错!";
|
||||
break;
|
||||
}
|
||||
} while (bytestoread == 0);
|
||||
|
||||
if (buffer[11] == 3)
|
||||
{
|
||||
if (buffer[15] == 1)
|
||||
{
|
||||
info = "发送的命令不是有效的FINS命令!";
|
||||
return "";
|
||||
}
|
||||
else if (buffer[15] == 2)
|
||||
{
|
||||
info = "发送的命令长度超出范围!";
|
||||
return "";
|
||||
}
|
||||
else if (buffer[15] == 3)
|
||||
{
|
||||
info = "PLC不支持该‘FINS’命令!";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
if (buffer[25] == WriteCommand[25])
|
||||
return DataTools.ByteToHexString(buffer, bytestoread);
|
||||
else
|
||||
{
|
||||
info = "PLC返回错误,返回值 " + buffer[0].ToString();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否成功写入命令到PLC
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Write2PlcSuccess()
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytestoread = 0;
|
||||
string info;
|
||||
int start = Environment.TickCount;
|
||||
|
||||
try
|
||||
{
|
||||
//lock (locker)
|
||||
{
|
||||
do
|
||||
{
|
||||
bytestoread = Stream.Read(buffer, 0, buffer.Length);
|
||||
if (Math.Abs(Environment.TickCount - start) >= 1000)
|
||||
{
|
||||
info = "PLC应答超时,请确认PLC连接线路及cpu是否有报错!";
|
||||
break;
|
||||
}
|
||||
} while (bytestoread == 0);
|
||||
|
||||
}
|
||||
if (buffer[25] == WriteCommand[25]) return true;
|
||||
else
|
||||
{
|
||||
info = "PLC返回错误,返回值 " + buffer[1].ToString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送连接字符串,获取PLC返回的DA1和SA1值
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool ConnectPrepare()
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream.Write(PrepareCmd, 0, PrepareCmd.Length);
|
||||
byte[] res = new byte[24];
|
||||
Stream.Read(res, 0, res.Length);
|
||||
DA1 = res[23];
|
||||
SA1 = res[19];
|
||||
}
|
||||
catch { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查命令帧中的EndCode
|
||||
/// </summary>
|
||||
/// <param name="Main">主码</param>
|
||||
/// <param name="Sub">副码</param>
|
||||
/// <param name="info">错误信息</param>
|
||||
/// <returns>指示程序是否可以继续进行</returns>
|
||||
private bool CheckEndCode(byte Main, byte Sub, out string info)
|
||||
{
|
||||
info = "";
|
||||
switch (Main)
|
||||
{
|
||||
case 0x00:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x00: return true;//the only situation of success
|
||||
case 0x01: info = "service canceled"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "local node not in network"; return false;
|
||||
case 0x02: info = "token timeout"; return false;
|
||||
case 0x03: info = "retries failed"; return false;
|
||||
case 0x04: info = "too many send frames"; return false;
|
||||
case 0x05: info = "node address range error"; return false;
|
||||
case 0x06: info = "node address duplication"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "destination node not in network"; return false;
|
||||
case 0x02: info = "unit missing"; return false;
|
||||
case 0x03: info = "third node missing"; return false;
|
||||
case 0x04: info = "destination node busy"; return false;
|
||||
case 0x05: info = "response timeout"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x03:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "communications controller error"; return false;
|
||||
case 0x02: info = "CPU unit error"; return false;
|
||||
case 0x03: info = "controller error"; return false;
|
||||
case 0x04: info = "unit number error"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x04:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "undefined command"; return false;
|
||||
case 0x02: info = "not supported by model/version"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x05:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "destination address setting error"; return false;
|
||||
case 0x02: info = "no routing tables"; return false;
|
||||
case 0x03: info = "routing table error"; return false;
|
||||
case 0x04: info = "too many relays"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "command too long"; return false;
|
||||
case 0x02: info = "command too short"; return false;
|
||||
case 0x03: info = "elements/data don't match"; return false;
|
||||
case 0x04: info = "command format error"; return false;
|
||||
case 0x05: info = "header error"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "area classification missing"; return false;
|
||||
case 0x02: info = "access size error"; return false;
|
||||
case 0x03: info = "address range error"; return false;
|
||||
case 0x04: info = "address range exceeded"; return false;
|
||||
case 0x06: info = "program missing"; return false;
|
||||
case 0x09: info = "relational error"; return false;
|
||||
case 0x0a: info = "duplicate data access"; return false;
|
||||
case 0x0b: info = "response too long"; return false;
|
||||
case 0x0c: info = "parameter error"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x02: info = "protected"; return false;
|
||||
case 0x03: info = "table missing"; return false;
|
||||
case 0x04: info = "data missing"; return false;
|
||||
case 0x05: info = "program missing"; return false;
|
||||
case 0x06: info = "file missing"; return false;
|
||||
case 0x07: info = "data mismatch"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x21:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "read-only"; return false;
|
||||
case 0x02: info = "protected , cannot write data link table"; return false;
|
||||
case 0x03: info = "cannot register"; return false;
|
||||
case 0x05: info = "program missing"; return false;
|
||||
case 0x06: info = "file missing"; return false;
|
||||
case 0x07: info = "file name already exists"; return false;
|
||||
case 0x08: info = "cannot change"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x22:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "not possible during execution"; return false;
|
||||
case 0x02: info = "not possible while running"; return false;
|
||||
case 0x03: info = "wrong PLC mode"; return false;
|
||||
case 0x04: info = "wrong PLC mode"; return false;
|
||||
case 0x05: info = "wrong PLC mode"; return false;
|
||||
case 0x06: info = "wrong PLC mode"; return false;
|
||||
case 0x07: info = "specified node not polling node"; return false;
|
||||
case 0x08: info = "step cannot be executed"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x23:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "file device missing"; return false;
|
||||
case 0x02: info = "memory missing"; return false;
|
||||
case 0x03: info = "clock missing"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x24:
|
||||
switch (Sub)
|
||||
{ case 0x01: info = "table missing"; return false; }
|
||||
break;
|
||||
case 0x25:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x02: info = "memory error"; return false;
|
||||
case 0x03: info = "I/O setting error"; return false;
|
||||
case 0x04: info = "too many I/O points"; return false;
|
||||
case 0x05: info = "CPU bus error"; return false;
|
||||
case 0x06: info = "I/O duplication"; return false;
|
||||
case 0x07: info = "CPU bus error"; return false;
|
||||
case 0x09: info = "SYSMAC BUS/2 error"; return false;
|
||||
case 0x0a: info = "CPU bus unit error"; return false;
|
||||
case 0x0d: info = "SYSMAC BUS No. duplication"; return false;
|
||||
case 0x0f: info = "memory error"; return false;
|
||||
case 0x10: info = "SYSMAC BUS terminator missing"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x26:
|
||||
switch (Sub)
|
||||
{
|
||||
case 0x01: info = "no protection"; return false;
|
||||
case 0x02: info = "incorrect password"; return false;
|
||||
case 0x04: info = "protected"; return false;
|
||||
case 0x05: info = "service already executing"; return false;
|
||||
case 0x06: info = "service stopped"; return false;
|
||||
case 0x07: info = "no execution right"; return false;
|
||||
case 0x08: info = "settings required before execution"; return false;
|
||||
case 0x09: info = "necessary items not set"; return false;
|
||||
case 0x0a: info = "number already defined"; return false;
|
||||
case 0x0b: info = "error will not clear"; return false;
|
||||
}
|
||||
break;
|
||||
case 0x30:
|
||||
switch (Sub)
|
||||
{ case 0x01: info = "no access right"; return false; }
|
||||
break;
|
||||
case 0x40:
|
||||
switch (Sub)
|
||||
{ case 0x01: info = "service aborted"; return false; }
|
||||
break;
|
||||
}
|
||||
info = "unknown exception";
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PLC初始化
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <returns></returns>
|
||||
private bool PlcInit()
|
||||
{
|
||||
bool flag = false;
|
||||
PlcClient = new TcpClient();
|
||||
IAsyncResult asyncResult = PlcClient.BeginConnect(IPAddr, Port, null, null);
|
||||
if (!asyncResult.AsyncWaitHandle.WaitOne(Timeout))
|
||||
{
|
||||
return flag;
|
||||
}
|
||||
PlcClient.EndConnect(asyncResult);
|
||||
|
||||
if (PlcClient != null)
|
||||
{
|
||||
Stream = PlcClient.GetStream();
|
||||
Stream.ReadTimeout = Timeout;
|
||||
Stream.WriteTimeout = Timeout;
|
||||
if (ConnectPrepare())
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接PLC
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <returns></returns>
|
||||
public bool PlcConnect(out string info)
|
||||
{
|
||||
info = "";
|
||||
try
|
||||
{
|
||||
if (PlcClient == null)
|
||||
{
|
||||
PlcInit();
|
||||
}
|
||||
if (!PlcClient.Connected) // 没连上的话重试一遍
|
||||
{
|
||||
PlcClient.Close();
|
||||
PlcClient = null;
|
||||
PlcInit();
|
||||
}
|
||||
return PlcClient.Connected;
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
info = "连接PLC失败\n" + exp.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开PLC连接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool DisConnect()
|
||||
{
|
||||
if (this.PlcClient == null)
|
||||
return true;
|
||||
if (!this.PlcClient.Connected)
|
||||
return true;
|
||||
|
||||
this.PlcClient.Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region 读
|
||||
|
||||
/// <summary>
|
||||
/// 读PLC字或位
|
||||
/// 读位时从左到右是低位到高位
|
||||
/// </summary>
|
||||
/// <param name="type">PLC内存区类型</param>
|
||||
/// <param name="startword">开始地址(字)</param>
|
||||
/// <param name="startbit">开始地址(位)</param>
|
||||
/// <param name="count">长度</param>
|
||||
/// <param name="result">返回的字符数组,每个元素表示一个字</param>
|
||||
/// <returns></returns>
|
||||
public bool Read(AreaType type, int startword, int startbit, int count, out string[] result)
|
||||
{
|
||||
result = new string[0];
|
||||
byte[] cmd = (byte[])ReadCommand.Clone();
|
||||
cmd[20] = DA1; //连接时获取到的DA1
|
||||
cmd[23] = SA1; //连接时获取到的SA1
|
||||
|
||||
// 内存类型
|
||||
cmd[28] = (byte)type;
|
||||
|
||||
// 读取起始地址
|
||||
byte[] bytesAddr = BitConverter.GetBytes((short)startword); //BitConverter转出来的Byte按从低位到高位排列
|
||||
cmd[29] = bytesAddr[1];
|
||||
cmd[30] = bytesAddr[0];
|
||||
cmd[31] = (byte)startbit;
|
||||
|
||||
// 读取长度
|
||||
byte[] bytesLength = BitConverter.GetBytes((short)count);
|
||||
cmd[32] = bytesLength[1];
|
||||
cmd[33] = bytesLength[0];
|
||||
|
||||
//开始读取
|
||||
lock (locker)
|
||||
{
|
||||
if (DataSend(cmd))
|
||||
{
|
||||
string res = DataRead();
|
||||
if (res.Length == 0)
|
||||
return false;
|
||||
|
||||
result = DataTools.StrToStrArray(res.Substring(60));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取DM区的字
|
||||
/// </summary>
|
||||
/// <param name="startword"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public bool ReadDWords(int startword, int count, out string[] result)
|
||||
{
|
||||
string[] res;
|
||||
bool isSucess = Read(AreaType.DM_Word, startword, 0, count, out res);
|
||||
result = res;
|
||||
return isSucess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取DM区的位
|
||||
/// </summary>
|
||||
/// <param name="startword"></param>
|
||||
/// <param name="startbit"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public bool ReadDBits(int startword, int startbit, int count, out string[] result)
|
||||
{
|
||||
string[] res;
|
||||
bool isSucess = Read(AreaType.DM_Bit, startword, startbit, count, out res);
|
||||
result = res;
|
||||
return isSucess;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 写
|
||||
|
||||
/// <summary>
|
||||
/// 写PLC字
|
||||
/// </summary>
|
||||
/// <param name="type">地址类型</param>
|
||||
/// <param name="startword">开始字地址</param>
|
||||
/// <param name="count">字数</param>
|
||||
/// <param name="paras">值</param>
|
||||
/// <returns>写入成功与否</returns>
|
||||
public bool WriteWords(AreaType type, int startword, int count, int[] paras)
|
||||
{
|
||||
byte[] hexadd = BitConverter.GetBytes(startword);
|
||||
byte[] sendCmd = WriteCommand.Concat(new byte[count * 2]).ToArray(); // 这里扩容sendCmd数组,不然会溢出
|
||||
|
||||
sendCmd[7] = (byte)(26 + count * 2);
|
||||
sendCmd[20] = DA1;
|
||||
sendCmd[23] = SA1;
|
||||
|
||||
// 内存类型
|
||||
sendCmd[28] = (byte)type;
|
||||
|
||||
// 写入起始地址
|
||||
byte[] bytesAddr = BitConverter.GetBytes((short)startword); //BitConverter转出来的Byte按从低位到高位排列
|
||||
sendCmd[29] = bytesAddr[1];
|
||||
sendCmd[30] = bytesAddr[0];
|
||||
sendCmd[31] = 0;
|
||||
|
||||
// 写入长度
|
||||
byte[] bytesLength = BitConverter.GetBytes((short)count);
|
||||
sendCmd[32] = bytesLength[1];
|
||||
sendCmd[33] = bytesLength[0];
|
||||
|
||||
byte[] hexPara;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
hexPara = BitConverter.GetBytes(paras[i]);
|
||||
sendCmd[34 + i * 2] = hexPara[1];
|
||||
sendCmd[34 + i * 2 + 1] = hexPara[0];
|
||||
}
|
||||
|
||||
lock (locker)
|
||||
{
|
||||
if (DataSend(sendCmd))
|
||||
{
|
||||
if (Write2PlcSuccess())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写PLC位
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="type">地址类型</param>
|
||||
/// <param name="startword">开始字地址</param>
|
||||
/// <param name="startbit">开始位地址</param>
|
||||
/// <param name="count">写入位数</param>
|
||||
/// <param name="paras">值</param>
|
||||
/// <returns>写入成功与否</returns>
|
||||
public bool WriteBits(AreaType type, int startword, int startbit, int count, bool[] paras)
|
||||
{
|
||||
byte[] hexadd = BitConverter.GetBytes(startword);
|
||||
byte[] sendCmd = WriteCommand.Concat(new byte[count]).ToArray(); // 这里扩容sendCmd数组,不然会溢出
|
||||
|
||||
// 命令长度
|
||||
sendCmd[7] = (byte)(26 + count);
|
||||
|
||||
sendCmd[20] = DA1;
|
||||
sendCmd[23] = SA1;
|
||||
|
||||
// 内存类型
|
||||
sendCmd[28] = (byte)type;
|
||||
|
||||
// 写入起始地址
|
||||
byte[] bytesAddr = BitConverter.GetBytes((short)startword); //BitConverter转出来的Byte按从低位到高位排列
|
||||
sendCmd[29] = bytesAddr[1];
|
||||
sendCmd[30] = bytesAddr[0];
|
||||
sendCmd[31] = (byte)startbit;
|
||||
|
||||
// 写入长度
|
||||
byte[] bytesLength = BitConverter.GetBytes((short)count);
|
||||
sendCmd[32] = bytesLength[1];
|
||||
sendCmd[33] = bytesLength[0];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
sendCmd[34 + i] = Convert.ToByte(paras[i]);
|
||||
}
|
||||
|
||||
lock (locker)
|
||||
{
|
||||
if (DataSend(sendCmd))
|
||||
{
|
||||
if (Write2PlcSuccess())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写D字
|
||||
/// </summary>
|
||||
/// <param name="startword"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="paras"></param>
|
||||
/// <returns></returns>
|
||||
public bool WriteDWords(int startword, int count, int[] paras)
|
||||
{
|
||||
return WriteWords(AreaType.DM_Word, startword, count, paras);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写D位
|
||||
/// </summary>
|
||||
/// <param name="startword"></param>
|
||||
/// <param name="startbit"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="paras"></param>
|
||||
/// <returns></returns>
|
||||
public bool WriteDBits(int startword, int startbit, int count, bool[] paras)
|
||||
{
|
||||
return WriteBits(AreaType.DM_Bit, startword, startbit, count, paras);
|
||||
}
|
||||
|
||||
public bool ReadString(int address, int count, out string str)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] res;
|
||||
bool isSucess = ReadDWords(address, count, out res);
|
||||
if (!isSucess)
|
||||
{
|
||||
str = "";
|
||||
return false;
|
||||
}
|
||||
byte[] bRes = res.Select(it => Convert.ToByte(it, 16)).ToArray();
|
||||
List<int> list = new List<int>();
|
||||
for (int i = 0; i < bRes.Length; i += 2)
|
||||
{
|
||||
list.Add((int)(bRes[i] << 8 | bRes[i + 1]));
|
||||
}
|
||||
str = GetQRCodeByData(list.ToArray());
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
str = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadFloat(int address, out float value)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] res;
|
||||
bool isSucess = ReadDWords(address, 2, out res);
|
||||
if (!isSucess)
|
||||
{
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
byte[] bRes = res.Select(it => Convert.ToByte(it, 16)).ToArray();
|
||||
if (bRes.Length != 4)
|
||||
{
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
int i = 0;
|
||||
value = BitConverter.ToSingle(new byte[] { bRes[i + 1], bRes[i], bRes[i + 3], bRes[i + 2] }, 0);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadFloats(int address, int count, out float[] values)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] res;
|
||||
bool isSucess = ReadDWords(address, count * 2, out res);
|
||||
if (!isSucess)
|
||||
{
|
||||
values = null;
|
||||
return false;
|
||||
}
|
||||
byte[] bRes = res.Select(it => Convert.ToByte(it, 16)).ToArray();
|
||||
if (bRes.Length != (count * 4))
|
||||
{
|
||||
values = null;
|
||||
return false;
|
||||
}
|
||||
List<float> list = new List<float>();
|
||||
for (int i = 0; i < bRes.Length; i += 4)
|
||||
{
|
||||
list.Add(BitConverter.ToSingle(new byte[] { bRes[i + 1], bRes[i], bRes[i + 3], bRes[i + 2] }, 0));
|
||||
}
|
||||
values = list.ToArray();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
values = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool WriteFloat(int address, float[] values)
|
||||
{
|
||||
List<int> writeValues = new List<int>();
|
||||
foreach (float f in values)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(f);
|
||||
writeValues.Add(BitConverter.ToInt32(new byte[] { bytes[0], bytes[1], 0, 0 }, 0));
|
||||
writeValues.Add(BitConverter.ToInt32(new byte[] { bytes[2], bytes[3], 0, 0 }, 0));
|
||||
}
|
||||
return WriteWords(AreaType.DM_Word, address, values.Length * 2, writeValues.ToArray());
|
||||
}
|
||||
|
||||
|
||||
public bool ReadShort(int address, out short value)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] res;
|
||||
bool isSucess = ReadDWords(address, 1, out res);
|
||||
if (!isSucess)
|
||||
{
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
byte[] bRes = res.Select(it => Convert.ToByte(it, 16)).ToArray();
|
||||
if (bRes.Length != 2)
|
||||
{
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
value = BitConverter.ToInt16(new byte[] { bRes[1], bRes[0] }, 0);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool ReadShorts(int address, int count, out short[] values)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] res;
|
||||
bool isSucess = ReadDWords(address, count, out res);
|
||||
if (!isSucess)
|
||||
{
|
||||
values = null;
|
||||
return false;
|
||||
}
|
||||
byte[] bRes = res.Select(it => Convert.ToByte(it, 16)).ToArray();
|
||||
if (bRes.Length != (count * 2))
|
||||
{
|
||||
values = null;
|
||||
return false;
|
||||
}
|
||||
List<short> list = new List<short>();
|
||||
for (int i = 0; i < bRes.Length; i += 2)
|
||||
{
|
||||
list.Add(BitConverter.ToInt16(new byte[] { bRes[i + 1], bRes[i] }, 0));
|
||||
}
|
||||
values = list.ToArray();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
values = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteShort(int address, short[] values)
|
||||
{
|
||||
List<int> writeValues = new List<int>();
|
||||
foreach (short f in values)
|
||||
{
|
||||
|
||||
writeValues.Add(f);
|
||||
}
|
||||
return WriteWords(AreaType.DM_Word, address, values.Length, writeValues.ToArray());
|
||||
}
|
||||
public bool WriteString(int address, string str, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
int[] aaa = GetDataByQRCode(str, count);
|
||||
return WriteDWords(address, count, aaa);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private int[] GetDataByQRCode(string qrcode, int totalCount)
|
||||
{
|
||||
byte[] byteList = new byte[2 * totalCount];
|
||||
|
||||
byte[] bytes = Encoding.ASCII.GetBytes(qrcode);
|
||||
for (int i = 0; i < byteList.Length; i++)
|
||||
{
|
||||
if (i >= bytes.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
byteList[i] = bytes[i];
|
||||
}
|
||||
|
||||
List<int> shortList = new List<int>();
|
||||
for (int i = 0; i < (2 * totalCount); i += 2)
|
||||
{
|
||||
//将字节数组转为int存入list
|
||||
shortList.Add(BitConverter.ToInt32(new byte[] { byteList[i], byteList[i + 1], 0x00, 0x00 }, 0));
|
||||
}
|
||||
return shortList.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将PLC中获取到的数据转成string
|
||||
/// </summary>
|
||||
/// <param name="qrcode"></param>
|
||||
/// <returns></returns>
|
||||
private string GetQRCodeByData(int[] qrcode)
|
||||
{
|
||||
List<byte> list = new List<byte>();
|
||||
for (int i = 0; i < qrcode.Length; i++)
|
||||
{
|
||||
//int中取两个字节存入list
|
||||
list.AddRange(BitConverter.GetBytes(qrcode[i]).Take(2));
|
||||
}
|
||||
//去掉多余的/0和空格 转为string
|
||||
string qrcodes = Encoding.ASCII.GetString(list.ToArray()).Trim('\0').Trim();
|
||||
return qrcodes;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user