using Bro.Common.Helper;
using Bro.Common.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Bro.Common.Helper.EnumHelper;
namespace Bro.Device.OmronFins
{
public class FinsFrame : FinsFrameBase
{
public bool IsUdp { get; set; } = true;
public FinsFrame() { }
///
/// 获取帧结构
///
/// 目标(PLC)网络号
/// 目标(PLC)节点
/// 目标(PLC)单元号
/// 源(PC)网络号
/// 源(PC)节点
/// 源(PC)单元号
public FinsFrame(byte dNA, byte dA1, byte dA2, byte sNA, byte sA1, byte sA2, bool isUdp = true)
{
DNA = dNA;
DA1 = dA1;
DA2 = dA2;
SNA = sNA;
SA1 = sA1;
SA2 = sA2;
IsUdp = isUdp;
}
public byte[] GetSendReadFrameBytes(PLC_ITEM item, int sid)
{
ICF = 0x80;
SRC = 0x01;
List textRange = BytesFrame(sid);
textRange.AddRange(GetTextRange(item));
return GetFrames(textRange);
}
private byte[] GetFrames(List textRange)
{
if (IsUdp)
{
return textRange.ToArray();
}
else
{
List data = new List()
{
0x46,0x49,0x4E,0x53,
0x00,0x00,
};
int length = 4 + 4 + textRange.Count;
data.AddRange(length.IntToBytes());
data.AddRange(new List()
{
0x00,0x00,0x00,0x02,
0x00,0x00,0x00,0x00,
});
data.AddRange(textRange);
return data.ToArray();
}
}
public byte[] GetSendWriteFrameBytes(PLC_ITEM item, int sid)
{
ICF = 0x80;
SRC = 0x02;
List textRange = BytesFrame(sid);
textRange.AddRange(GetTextRange(item));
#region 添加写入内容
byte[] writeData;
switch (item.ITEM_VALUE_TYPE)
{
case (int)PLCItemType.Bool:
{
writeData = ConvertIntToByte(int.Parse(item.ITEM_VALUE), item.ITEM_LENGTH, 1);
textRange.AddRange(writeData);
}
break;
case (int)PLCItemType.Integer:
{
writeData = ConvertIntToByte(int.Parse(item.ITEM_VALUE), item.ITEM_LENGTH, 2, true);
textRange.AddRange(writeData);
}
break;
case (int)PLCItemType.String:
{
byte[] bs = System.Text.Encoding.Default.GetBytes(item.ITEM_VALUE);
writeData = new byte[item.ITEM_LENGTH * 2];
bs.CopyTo(writeData, 0);
textRange.AddRange(writeData);
}
break;
default:
break;
}
#endregion
return GetFrames(textRange);
}
public byte[] GetTcpRequestFrame(int nodeNum = 0)
{
byte[] data = new byte[]
{
0x46,0x49,0x4E,0x53,
0x00,0x00,0x00,0x0c,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,(byte)nodeNum
};
return data;
}
public int AnalyseTcpRequestRespond(byte[] data, out string msg)
{
msg = "";
if (data.Length != 20)
{
msg = "返回帧长度错误";
return -1;
}
if (data[0] != 0x46 || data[1] != 0x49 || data[2] != 0x4E || data[3] != 0x53)
{
msg = "返回帧头标识错误";
return -1;
}
List errorCode = data.Skip(4 + 4 + 4).Take(4).ToList();
if (errorCode.Any(u => u != 0x00))
{
msg = string.Join("", errorCode);
return -1;
}
return data.Skip(4 + 4 + 4 + 4 + 3).Take(1).ElementAt(0);
}
//Dictionary oldItemValue = new Dictionary();
//ConcurrentDictionary oldItemValue = new ConcurrentDictionary();
///
///
///
///
///
/// true:数值有变化 false:数值无变化
//public bool CheckReceivedItems(byte[] bytes, PLC_ITEM item)
//{
// if (bytes == null || bytes.Length == 0 || bytes.All(b => b == 0))
// return false;
// List byteList = bytes.ToList();
// //List beginIndexList = new List();
// int beginIndex = -1;
// for (int i = 0; i < bytes.Length - 5; i++)
// {
// if (bytes[i] == 0xC0
// && bytes[i + 1] == 0x00
// && bytes[i + 2] == 0x02
// && bytes[i + 3] == SNA
// && bytes[i + 4] == SA1
// && bytes[i + 5] == SA2)
// {
// //beginIndexList.Add(i);
// beginIndex = i;
// break;
// }
// }
// //if (beginIndexList.Count < items.Count)
// //{
// // throw new UserException("欧姆龙PLC通讯可能出现丢帧现象", LogType.Exception_Error);
// //}
// if (beginIndex == -1)
// {
// throw new ProcessException("欧姆龙PLC通讯帧错误", null);
// }
// //for (int i = 0; i < beginIndexList.Count; i++)
// //{
// // int takeCount = 0;
// // if (i < beginIndexList.Count - 1)
// // {
// // takeCount = beginIndexList[i + 1] - beginIndexList[i];
// // }
// // List singleBytes;
// // if (takeCount == 0)
// // {
// // singleBytes = bytes.Skip(beginIndexList[i]).ToList();
// // }
// // else
// // {
// // singleBytes = bytes.Skip(beginIndexList[i]).Take(takeCount).ToList();
// // }
// //}
// List singleBytes = bytes.Skip(beginIndex).ToList();
// item.OpTimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// #region 如果该帧是写入指令的回复帧
// if (singleBytes[11] == 0x02)
// {
// //MRES SRES检查
// if (!(singleBytes[12] == 0x00 && singleBytes[13] == 0x00))
// {
// //throw new UserException("欧姆龙PLC写入错误", LogType.Exception_Error);
// }
// return true;
// }
// #endregion
// #region 如果该帧是读取指令的回复帧
// else if (singleBytes[11] == 0x01)
// {
// byte[] data;
// //string oldValue = item.ITEM_VALUE;
// //if (!oldItemValue.Keys.Contains(item.ID))
// //{
// // oldItemValue[item.ID] = item.ITEM_VALUE;
// //}
// oldItemValue.GetOrAdd(item.ID, item.ITEM_VALUE);
// string newValue = null;
// if (item.ITEM_VALUE_TYPE == (int)PLCItemType.Bool)
// {
// data = new byte[item.ITEM_LENGTH];
// singleBytes.CopyTo(14, data, 0, data.Length);
// newValue = ConvertByteToInt(data, 1).ToString();
// }
// else if (item.ITEM_VALUE_TYPE == (int)PLCItemType.Integer)
// {
// data = new byte[item.ITEM_LENGTH * 2];
// singleBytes.CopyTo(14, data, 0, data.Length);
// newValue = ConvertByteToInt(data, 2, true).ToString();
// }
// else if (item.ITEM_VALUE_TYPE == (int)PLCItemType.String)
// {
// data = new byte[item.ITEM_LENGTH * 2];
// singleBytes.CopyTo(14, data, 0, data.Length);
// newValue = System.Text.Encoding.Default.GetString(data);
// }
// if (oldItemValue[item.ID] != newValue)
// {
// //oldItemValue[item.ID] = item.ITEM_VALUE = newValue;
// oldItemValue.AddOrUpdate(item.ID, newValue, (a, b) => { return newValue; });
// item.ITEM_VALUE = newValue;
// //Task.Run(() => item.OnPLCItemDataChanged?.Invoke(DateTime.Now, oldValue, newValue));
// return true;
// }
// //return oldValue != newValue;
// }
// return false;
// #endregion
//}
public List AnalyseReceivedItems(byte[] bytes, PLC_ITEM item)
{
if (!IsUdp)
{
List errorCode = bytes.Skip(4 + 4 + 4).Take(4).ToList();
if (errorCode.Any(u => u != 0x00))
{
throw new ProcessException($"返回异常,错误码{string.Join("", errorCode)}", null);
}
bytes = bytes.Skip(4 + 4 + 4 + 4).ToArray();
}
List list = new List();
if (bytes == null || bytes.Length == 0 || bytes.All(b => b == 0))
return null;
List byteList = bytes.ToList();
int beginIndex = -1;
for (int i = 0; i < bytes.Length - 5; i++)
{
if (bytes[i] == 0xC0
&& bytes[i + 1] == 0x00
&& bytes[i + 2] == 0x02
&& bytes[i + 3] == SNA
&& bytes[i + 4] == SA1
&& bytes[i + 5] == SA2)
{
//beginIndexList.Add(i);
beginIndex = i;
break;
}
}
if (beginIndex == -1)
{
throw new ProcessException("欧姆龙PLC通讯帧错误", null);
}
List singleBytes = bytes.Skip(beginIndex).ToList();
#region 如果该帧是写入指令的回复帧
if (singleBytes[11] == 0x02)
{
//MRES SRES检查
if (!(singleBytes[12] == 0x00 && singleBytes[13] == 0x00))
{
//throw new UserException("欧姆龙PLC写入错误", LogType.Exception_Error);
}
return list;
}
#endregion
#region 如果该帧是读取指令的回复帧
else if (singleBytes[11] == 0x01)
{
if (item.ITEM_VALUE_TYPE == (int)PLCItemType.Integer)
{
byte[] data = new byte[item.ITEM_LENGTH * 2];
singleBytes.CopyTo(14, data, 0, data.Length);
for (int i = 0; i < data.Length; i += 2)
{
byte[] res = new byte[2];
Array.Copy(data, i, res, 0, 2);
list.Add(res.BytesToInt());
}
return list;
}
else
{
return null;
}
}
#endregion
return null;
}
protected List GetTextRange(PLC_ITEM item)
{
List textRange = new List();
int wordAddress = 0;
int byteAddress = 0;
//针对CJ和CS系列
if (item.ADDRESS.ToUpper().StartsWith("DM") || item.ADDRESS.ToUpper().StartsWith("D"))
{
//AreaCode = 0x82;
textRange.Add(0x82);
wordAddress = Convert.ToInt16(item.ADDRESS.Replace("D", "").Replace("M", ""));
}
else if (item.ADDRESS.ToUpper().StartsWith("W"))
{
if (item.ITEM_VALUE_TYPE == (int)PLCItemType.Bool)
{
//AreaCode = 0x31;
textRange.Add(0x31);
string wholeAddress = item.ADDRESS.Replace("W", "");
int dotIndex = wholeAddress.IndexOf(".");
wordAddress = Convert.ToInt16(wholeAddress.Substring(0, dotIndex));
byteAddress = Convert.ToInt16(wholeAddress.Substring(dotIndex + 1));
}
else
{
//AreaCode = 0xB1;
textRange.Add(0xB1);
wordAddress = Convert.ToInt16(item.ADDRESS.Replace("W", ""));
}
}
else if (item.ADDRESS.ToUpper().StartsWith("CIO"))
{
//AreaCode = 0x30;
textRange.Add(0x30);
string wholeAddress = item.ADDRESS.Replace("CIO", "");
int dotIndex = wholeAddress.IndexOf(".");
wordAddress = Convert.ToInt16(wholeAddress.Substring(0, dotIndex));
byteAddress = Convert.ToInt16(wholeAddress.Substring(dotIndex + 1));
}
if (wordAddress == 0 && byteAddress == 0)
{
throw new ProcessException("欧姆龙PLC监听地址设置错误", null);
}
//字地址
//string high2 = wordAddress.ToString("X4").Substring(0, 2);
//string low2 = wordAddress.ToString("X4").Substring(2, 2);
//textRange.Add((byte)Convert.ToInt16(high2, 16));
//textRange.Add((byte)Convert.ToInt16(low2, 16));
textRange.AddRange(ConvertIntToByte(wordAddress, 1, 2));
//位地址
textRange.Add((byte)byteAddress);
//读取项目个数
//int opItemNum = 1;
//if (item.ITEM_VALUE_TYPE == (int)PLCItemType.String)
//{
// opItemNum = item.ITEM_VALUE.Length;
//}
//textRange.AddRange(ConvertIntTo2Byte(opItemNum));
textRange.AddRange(ConvertIntToByte(item.ITEM_LENGTH, 1, 2));
return textRange;
}
///
/// 将数字转换为字节数组
///
/// 需要转换的数字
/// 转换数据长度。 如果是位操作 结果长度和数据长度一致;如果是字操作 结果长度是数据长度两倍
/// 1:表示是位操作 2:表示是字操作
///
protected byte[] ConvertIntToByte(int sourceInt, int dataLength = 1, int bitLength = 1, bool inverseHL = false)
{
byte[] bs;
//位操作
if (bitLength == 1)
{
bs = new byte[dataLength];
for (int i = 0; i < bs.Length; i++)
{
bs[i] = (byte)((sourceInt >> ((bs.Length - i - 1) * 2)) & 3); //取末两位
}
}
else //字操作
{
string formatStr = "X" + dataLength * 4;
string sourceXStr = sourceInt.ToString(formatStr);
bs = new byte[dataLength * 2];
if (inverseHL)
{
sourceXStr = ReverseStr4(sourceXStr);
}
for (int i = 0; i < bs.Length; i++)
{
bs[i] = (byte)Convert.ToInt32(sourceXStr.Substring(i * 2, 2), 16);
}
}
return bs;
}
private string ReverseStr4(string sourceXStr)
{
string result = "";
for (int i = 0; i < sourceXStr.Length - 3; i = i + 4)
{
result = result.Insert(0, sourceXStr.Substring(i, 4));
}
return result;
}
protected int ConvertByteToInt(byte[] bytes, int length = 1, bool inverseHL = false)
{
if (length == 1)
{
int result = 0;
for (int i = 0; i < bytes.Length; i++)
{
result += (bytes[i] << ((bytes.Length - i - 1) * 2));
}
return result;
}
else
{
string xStr = "";
Array.ForEach(bytes, b =>
{
xStr += b.ToString("X2");
});
if (inverseHL)
{
xStr = ReverseStr4(xStr);
}
return Convert.ToInt32(xStr, 16);
}
}
}
}