using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Bro.Common.Helper; using System.Reflection; using static Bro.Common.Helper.EnumHelper; using Bro.Common.Model; namespace SchneiderPLC_ModbusTcp { #region DataFrame public interface IModbusDataFrame { ModbusOrder Order { get; set; } int Address { get; set; } int Length { get; set; } List OpValue { get; set; } byte[] Frame { get; set; } string GetFrameString(); } public class ModbusDataFrame_Send : IModbusDataFrame { public ModbusOrder Order { get; set; } private int address = -1; public int Address { get { return address; } set { if (value != address) { address = value; SetFrame(); } } } private int length = -1; public int Length { get { return length; } set { if (value != length) { length = value; SetFrame(); } } } private List sendValue; public List OpValue { get { return sendValue; } set { if (value != sendValue) { sendValue = value; SetFrame(); } } } public byte[] Frame { get; set; } public ModbusDataFrame_Send() { } public ModbusDataFrame_Send(ModbusOrder order, int address, int length, List value) { Order = order; Address = address; Length = length; OpValue = value; } public void SetFrame(bool enforce = false) { if (enforce || (Address != -1 && Length != -1 && OpValue != null)) { FrameAttribue attr = Order.GetType().GetField(Order.ToString()).GetCustomAttribute(); if (attr != null) { Frame = attr.GetSendFrame(Address, Length, OpValue); } } } public string GetFrameString() { return string.Format("Order:{0};Addr:{1};Length:{2},Data:{3}", Order.ToString(), Address, Length, string.Join(",", OpValue ?? new List())); } } public class ModbusDataFrame_Receive : IModbusDataFrame { //private int address = -1; public int Address { get; set; } //{ // get // { // if (address == -1) // { // byte[] addressBytes = new byte[2]; // Array.Copy(Frame, 1, addressBytes, 0, 2); // address = addressBytes.BytesToInt(); // } // return address; // } // set // { // //throw new NotImplementedException(); // } //} private byte[] frame = null; public byte[] Frame { get { return frame; } set { if (value != null) { frame = value; AnalyzeReceivedData(); } } } //private int length = 0; public int Length { get; set; } //{ // get // { // if (length == 0) // { // } // return length; // } // set // { // //throw new NotImplementedException(); // } //} //private ModbusOrder order = ModbusOrder.Read_Coil; public ModbusOrder Order { get; set; } //private List opValue; public List OpValue { get; set; } //{ // get // { // if (opValue == -1) // { // } // return opValue; // } // set // { // //throw new NotImplementedException(); // } //} public ModbusDataFrame_Receive() { } public ModbusDataFrame_Receive(byte[] datas) { Frame = datas; } public void AnalyzeReceivedData() { Order = (ModbusOrder)Frame[0]; FrameAttribue attr = Order.GetType().GetField(Order.ToString()).GetCustomAttribute(); if (attr != null) { List valueList = new List(); int lengthResult = 0; int addressResult = 0; bool flag = attr.AnalyzeReceiveFrame(Frame, out valueList, out addressResult, out lengthResult); if (!flag) { //throw new Common.Helper.UserException("Modbus返回数据解析失败"); throw new Exception("Modbus返回数据解析失败"); } OpValue = valueList; Address = addressResult; Length = lengthResult; } else { //throw new Common.Helper.UserException("Modbus返回数据不在解析范围中"); throw new Exception("Modbus返回数据不在解析范围中"); } } public string GetFrameString() { return string.Format("Order:{0};Addr:{1};Length:{2},Data:{3}", Order.ToString(), Address, Length, string.Join(",", OpValue ?? new List())); } } #endregion #region Frame public interface IModbusFrame { #region MBAP Head byte[] ModbusFlag { get; set; } int Head { get; set; } int Length { get; set; } int UnitNum { get; set; } #endregion #region Modbus Body IModbusDataFrame BodyFrame { get; set; } #endregion byte[] Frame { get; set; } string GetFrameString(); } public class ModbusFrame_Send : IModbusFrame { #region MBAP Head public byte[] ModbusFlag { get; set; } = { 0x00, 0x00 }; private int head = 0; public int Head { get { return head; } set { if (head != value) { head = value; SetFrame(); } } } private int length = 0; public int Length { get { return length; } set { if (length != value) { length = value; SetFrame(); } } } private int unitNum = 1; public int UnitNum { get { return unitNum; } set { if (unitNum != value) { unitNum = value; SetFrame(); } } } #endregion #region Modbus Body private IModbusDataFrame bodyFrame = null; public IModbusDataFrame BodyFrame { get { return bodyFrame; } set { if (bodyFrame != value) { bodyFrame = value; SetFrame(); } } } #endregion public byte[] Frame { get; set; } public void SetFrame() { if (BodyFrame == null || BodyFrame.Frame == null || BodyFrame.Frame.Length == 0) { return; } List all = new List(); #region MBAP all.AddRange(Head.IntToBytes()); all.AddRange(ModbusFlag); all.AddRange(new byte[] { 0x00, 0x00 }); //预设长度 all.AddRange(UnitNum.IntToBytes(1)); #endregion all.AddRange(BodyFrame.Frame); Length = BodyFrame.Frame.Length + 1; byte[] lengthBytes = Length.IntToBytes(); all[2 + 2 + 0] = lengthBytes[0]; all[2 + 2 + 1] = lengthBytes[1]; Frame = all.ToArray(); } public ModbusFrame_Send() { } public ModbusFrame_Send(ModbusOrder _order, int _address, int _length, List valueList, int _headId = 1, int _unitNum = 1) { Head = _headId; UnitNum = _unitNum; BodyFrame = new ModbusDataFrame_Send(_order, _address, _length, valueList); } public ModbusFrame_Send(PLCItem item, int _unitNum = 1, int _headId = 1) { ModbusOrder order = ModbusOrder.Read_Coil; if (((int)item.PLCOpType & (int)PLCOpType.Read) == (int)PLCOpType.Read) { switch (item.Address[0]) { case '0': order = ModbusOrder.Read_Coil; break; case '1': order = ModbusOrder.Read_Input; break; case '3': order = ModbusOrder.Read_InputRegister; break; case '4': order = ModbusOrder.Read_HoldingRegister; break; } } else { switch (item.Address[0]) { case '1': if (item.ItemLength > 1) { order = ModbusOrder.Write_MultipleOutputs; } else { order = ModbusOrder.Write_SingleOutput; } break; case '4': if (item.ItemLength > 1) { order = ModbusOrder.Write_MultipleRegister; } else { order = ModbusOrder.Write_SingleRegister; } break; } } //int address = Convert.ToInt16(item.ADDRESS.Substring(1), 16); int address = int.Parse(item.Address.Substring(1)); //address = address - 1; //PLC地址比Modbus地址少一位。例如PLC40001读取Modbus40000 Head = _headId; UnitNum = _unitNum; //List valueList = new List(); //if (!string.IsNullOrWhiteSpace(item.ItemValues)) //{ // valueList = item.ItemValues.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList().ConvertAll(s => int.Parse(s)).ToList(); //} BodyFrame = new ModbusDataFrame_Send(order, address, item.ItemLength, item.ItemValues); } public string GetFrameString() { string desc = string.Format("Send:{0}\r\n", string.Join(" ", Array.ConvertAll(Frame, b => b.ToString("X2")))); desc += string.Format("DataFrame:{0}\r\n", BodyFrame?.GetFrameString()); return desc; } } public class ModbusFrame_Receive : IModbusFrame { private byte[] frame = null; public byte[] Frame { get { return frame; } set { if (value != null) { frame = value; AnalyzeFrame(); } } } //private int head = 0; public int Head { get; set; } //{ // get // { // if (head == 0) // { // byte[] headBytes = new byte[2]; // Array.Copy(Frame, 0, headBytes, 0, 2); // head = headBytes.BytesToInt(); // } // return head; // } // set // { // //throw new NotImplementedException(); // } //} //private int length = 0; public int Length { get; set; } //{ // get // { // if (length == 0) // { // byte[] lengthBytes = new byte[2]; // Array.Copy(Frame, 4, lengthBytes, 0, 2); // length = lengthBytes.BytesToInt(); // } // return length; // } // set // { // //throw new NotImplementedException(); // } //} public byte[] ModbusFlag { get; set; } = { 0x00, 0x00 }; //private int unitNum = -1; public int UnitNum { get; set; } //{ // get // { // if (unitNum == -1) // { // unitNum = Frame[6]; // } // return unitNum; // } // set // { // //throw new NotImplementedException(); // } //} //private IModbusDataFrame bodyFrame = null; public IModbusDataFrame BodyFrame { get; set; } public ModbusFrame_Receive() { } public ModbusFrame_Receive(byte[] datas) { Frame = datas; } public void AnalyzeFrame() { byte[] headBytes = new byte[2]; Array.Copy(Frame, 0, headBytes, 0, 2); Head = headBytes.BytesToInt(); byte[] lengthBytes = new byte[2]; Array.Copy(Frame, 4, lengthBytes, 0, 2); Length = lengthBytes.BytesToInt(); UnitNum = Frame[6]; BodyFrame = new ModbusDataFrame_Receive(Frame.Skip(2 + 2 + 2 + 1).ToArray()); } public string GetFrameString() { string desc = string.Format("Rec:{0}\r\n", string.Join(" ", Array.ConvertAll(Frame, b => b.ToString("X2")))); desc += string.Format("DataFrame:{0}\r\n", BodyFrame?.GetFrameString()); return desc; } } #endregion public enum ModbusOrder { [FrameAttribue(0x01, true, false, true)] Read_Coil = 0x01, [FrameAttribue(0x02, false, true, true)] Read_Input = 0x02, [FrameAttribue(0x03, false, true, true)] Read_HoldingRegister = 0x03, [FrameAttribue(0x04, false, true, true)] Read_InputRegister = 0x04, [FrameAttribue(0x05, true, false, false)] Write_SingleOutput = 0x05, [FrameAttribue(0x06, false, false, false)] Write_SingleRegister = 0x06, [FrameAttribue(0x0f, true, true, false)] Write_MultipleOutputs = 0x0f, [FrameAttribue(0x10, false, true, false)] Write_MultipleRegister = 0x10, //[FrameAttribue(0x17, true, false, true)] //RW_MultipleRegister = 0x17, } public class FrameAttribue : Attribute { public byte Code { get; set; } public bool IsRead { get; set; } public bool IsMultiple { get; set; } public bool IsCoil { get; set; } public FrameAttribue(byte code, bool isCoil, bool isMultiple, bool isRead = true) { Code = code; IsRead = isRead; IsMultiple = isMultiple; IsCoil = isCoil; } public byte[] GetSendFrame(int address, int length, List valueList) { List all = new List(); all.Add(Code); all.AddRange(address.IntToBytes()); if (IsRead) { all.AddRange(length.IntToBytes()); } else { if (!IsMultiple) { if (IsCoil) { all.AddRange(valueList[0] == 1 ? new byte[] { 0xff, 0x00 } : new byte[] { 0x00, 0x00 }); } else { all.AddRange(valueList[0].IntToBytes()); } } else { //int divide = valueList.Count / 8; //int remainder = length % 8; //if (remainder > 0) //{ // divide++; //} //all.AddRange(divide.IntToBytes(1)); ////all.AddRange(valueList.IntToBytes(divide)); all.AddRange(valueList.Count.IntToBytes(2));//寄存器数量 if (IsCoil) { int divide = valueList.Count / 8; int remainder = length % 8; if (remainder > 0) { divide++; } all.AddRange(divide.IntToBytes(1)); //字节长度 for (int i = 0; i < divide; i++) { string s = ""; for (int j = 0; j < 8; j++) { int index = j + i * 8; if (valueList.Count > index) { s = valueList[index].ToString() + s; } else { s = "0" + s; } } all.Add((byte)Convert.ToInt16(s, 2)); } } else { all.Add((byte)(valueList.Count * 2));//字节长度 valueList.ForEach(u => { all.AddRange(u.IntToBytes()); }); } } } return all.ToArray(); } public bool AnalyzeReceiveFrame(byte[] data, out List opValue, out int address, out int length) { opValue = new List(); address = -1; length = 0; if (IsRead) { if (IsCoil) { length = data[1]; for (int i = 0; i < length; i++) { int index = i + 2; //头两位是Code和Length if (index > data.Length) { return false; } int value8 = data[index]; for (int j = 0; j < 8; j++) { opValue.Add((value8 >> j) & 0x01); } } } else { length = data[1] / 2; for (int i = 0; i < length; i++) { byte[] res = new byte[2]; Array.Copy(data, i * 2 + 2, res, 0, 2); opValue.Add(res.BytesToInt()); } } } else { if (data.Length < 5) { return false; } byte[] addbytes = new byte[2]; Array.Copy(data, 1, addbytes, 0, 2); address = addbytes.BytesToInt(); if (IsMultiple) { byte[] writeLengthBytes = new byte[2]; Array.Copy(data, 3, writeLengthBytes, 0, 2); length = writeLengthBytes.BytesToInt(); } else { byte[] writeValueBytes = new byte[2]; Array.Copy(data, 3, writeValueBytes, 0, 2); opValue.Add(writeValueBytes.BytesToInt()); } } return true; } } //public class SendFrameAttribue : FrameAttribue //{ // public SendFrameAttribue(byte code, bool isCoil, bool isMultiple, bool isRead = true) : base(code, isCoil, isMultiple, isRead) // { // } // public byte[] GetSendFrame(int address, int length, List valueList) // { // List all = new List(); // all.Add(Code); // all.AddRange(address.IntToBytes()); // if (IsRead) // { // all.AddRange(length.IntToBytes()); // } // else // { // if (!IsMultiple) // { // if (IsCoil) // { // all.AddRange(valueList[0] == 1 ? new byte[] { 0xff, 0x00 } : new byte[] { 0x00, 0x00 }); // } // else // { // all.AddRange(valueList[0].IntToBytes()); // } // } // else // { // //int divide = valueList.Count / 8; // //int remainder = length % 8; // //if (remainder > 0) // //{ // // divide++; // //} // //all.AddRange(divide.IntToBytes(1)); // ////all.AddRange(valueList.IntToBytes(divide)); // all.AddRange(valueList.Count.IntToBytes(1));//寄存器数量 // if (IsCoil) // { // int divide = valueList.Count / 8; // int remainder = length % 8; // if (remainder > 0) // { // divide++; // } // all.AddRange(divide.IntToBytes(1)); //字节长度 // for (int i = 0; i < divide; i++) // { // string s = ""; // for (int j = 0; j < 8; j++) // { // int index = j + i * 8; // if (valueList.Count > index) // { // s = valueList[index].ToString() + s; // } // else // { // s = "0" + s; // } // } // all.Add((byte)Convert.ToInt16(s, 2)); // } // } // else // { // all.Add((byte)(valueList.Count * 2));//字节长度 // valueList.ForEach(u => // { // all.AddRange(u.IntToBytes()); // }); // } // } // } // return all.ToArray(); // } //} //public class ReceiveFrameAttribue : FrameAttribue //{ // public ReceiveFrameAttribue(byte code, bool isCoil, bool isMultiple, bool isRead = true) : base(code, isCoil, isMultiple, isRead) // { // } // public bool GetReceiveFrame(byte[] data, out List readValue, out int address, out int writeLength, out int writeValue) // { // readValue = new List(); // address = -1; // writeLength = 1; // writeValue = -1; // if (data[0] != Code) // { // return false; // } // if (IsRead) // { // int dataLength = data[1]; // if (IsCoil) // { // for (int i = 0; i < dataLength; i++) // { // int index = i + 2; // if (index > data.Length) // { // return false; // } // int value8 = data[index]; // for (int j = 0; j < 8; j++) // { // readValue.Add((value8 >> j) & 0x01); // } // } // } // else // { // for (int i = 0; i < dataLength; i++) // { // byte[] res = new byte[2]; // Array.Copy(data, i * 2 + 2, res, 0, 2); // readValue.Add(res.BytesToInt()); // } // } // } // else // { // if (data.Length < 5) // { // return false; // } // byte[] addbytes = new byte[2]; // Array.Copy(data, 1, addbytes, 0, 2); // address = addbytes.BytesToInt(); // if (IsMultiple) // { // byte[] writeLengthBytes = new byte[2]; // Array.Copy(data, 3, writeLengthBytes, 0, 2); // writeLength = writeLengthBytes.BytesToInt(); // } // else // { // byte[] writeValueBytes = new byte[2]; // Array.Copy(data, 3, writeValueBytes, 0, 2); // writeValue = writeValueBytes.BytesToInt(); // } // } // return true; // } //} }