using DBHelper_SqlSugar; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using WCS.Entity; namespace WCS.Core { public class DataBlock : EntityEx { protected byte[] Data; //{ // get { return DataServer.Get(Entity); } //} private List Values = new List(); internal event Action DataChanged; /// /// 是否失败,默认成功 /// private bool failed = false; public DataBlock(WCS_DATABLOCK entity) : base(entity) { } private DateTime AliveTime = DateTime.Now; public void DataRefresh() { var sw = new Stopwatch(); try { if (Entity.NOUPDATE && Data != null) return; if (failed && (DateTime.Now - AliveTime).TotalMilliseconds < 3000) { throw new Exception(Entity.NAME + "连接失败"); } AliveTime = DateTime.Now; byte[] data = null; lock (Entity.PLC) { sw.Start(); data = Entity.PLC.Ex().Accessor.ReadBytes((ushort)Entity.NO, 0, (ushort)Entity.LENGTH, (ushort)Entity.DATALENGTH); sw.Stop(); } failed = false; if (Data != null && data.SequenceEqual(Data)) return; Data = data; Db.Do(db => { DataChanged?.Invoke(db, Data); }); } catch (Exception) { sw.Stop(); failed = true; throw; } finally { if (sw.ElapsedMilliseconds > 500) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"{Entity.PLC.NAME}{Entity.PLC.IP}访问耗时:{sw.ElapsedMilliseconds}"); Console.ResetColor(); } } } public PlcItem Regist(string objid, string name, int start, byte arrLen = 1, byte strLen = 0) { var pv = new PlcItem(objid, name, this, start, arrLen, strLen); Values.Add(pv); return pv; } private ushort GetByteStart(int bitStart) { var res = bitStart / 8; return (ushort)res; } private ushort GetBitIndex(int bitStart) { return (ushort)(bitStart % 8); } #region 读取 public T Read(int bitStart, int strLength, int arrLength) { return (T)Read(typeof(T), ref bitStart, strLength, arrLength); } private object Read(Type type, ref int bitStart, int strLength, int arrLength) { if (failed) throw new Exception(this.Entity.NAME + "连接失败"); if (type.IsArray) { var t = type.GetElementType(); if (t.IsArray) { throw new Exception("只支持一维数组"); } var arr = Array.CreateInstance(t, arrLength); for (int i = 0; i < arr.Length; i++) { var value = Read(t, ref bitStart, strLength, 0); arr.SetValue(value, i); } return arr; } else if (typeof(IList).IsAssignableFrom(type)) { var t = type.GetGenericArguments().First(); var res = Activator.CreateInstance(type) as IList; while (bitStart < Entity.LENGTH * 8) { var value = Read(t, ref bitStart, strLength, 0); res.Add(value); } return res; } else if (type == typeof(bool)) { return ReadBit(ref bitStart); } else if (type == typeof(string)) { return ReadString(ref bitStart, strLength); } else if (type.IsEnum) { return ReadEnum(type, ref bitStart); } else if (type.IsPrimitive) { var revers = Entity.PLC.TYPE == PLCType.西门子; return ReadPrimitive(type, ref bitStart, revers); //var revers = Entity.PLC.TYPE == PLCType.西门子; //return ReadPrimitive(type, ref bitStart, false); } else { if (type.IsValueType) { //ushort size = (ushort)Marshal.SizeOf(type); //var s = bitStart; //var bytes = ReadBytes(ref s, size).Reverse().ToArray(); //var o = ByteToStruct(type, bytes); var res = Activator.CreateInstance(type); foreach (var p in type.GetProperties()) { var value = Read(p.PropertyType, ref bitStart, strLength, arrLength); p.SetValue(res, value); } return res; } else throw new Exception("类型不支持"); } } public static object ByteToStruct(Type type, byte[] dataBuffer) { int size = Marshal.SizeOf(type); IntPtr allocIntPtr = Marshal.AllocHGlobal(size); try { Marshal.Copy(dataBuffer, 0, allocIntPtr, size); return Marshal.PtrToStructure(allocIntPtr, type); } finally { Marshal.FreeHGlobal(allocIntPtr); } } private string ReadString(ref int bitStart, int strLen) { if (Entity.PLC.TYPE == PLCType.西门子) { var data = ReadBytes(ref bitStart, (ushort)(strLen + 2)); var len = data[1]; data = data.Skip(2).Take(len).ToArray(); var str = Configs.StringEncoding.GetString(data); return str; } else { var data = ReadBytes(ref bitStart, (ushort)strLen); var str = Configs.StringEncoding.GetString(data); return str; } } private object ReadEnum(Type enumType, ref int bitStart) { var type = enumType.GetEnumUnderlyingType(); var reverse = false; if (enumType.GetCustomAttribute() == null) { reverse = Entity.PLC.TYPE == PLCType.西门子; } var value = ReadPrimitive(type, ref bitStart, reverse); var res = Enum.Parse(enumType, value.ToString()); return res; } private object ReadPrimitive(Type type, ref int bitStart, bool reverse) { var size = (ushort)Marshal.SizeOf(type); if (type == typeof(bool)) size = 1; var data = ReadBytes(ref bitStart, size); if (reverse) data = data.Reverse().ToArray(); if (Entity.CODE == "SRM2_521" && type == typeof(short)) { var c = 1; } if (type == typeof(byte)) { return data.First(); } else if (type == typeof(bool)) { return BitConverter.ToBoolean(data, 0); } else if (type == typeof(char)) { return BitConverter.ToChar(data, 0); } else if (type == typeof(short)) { return BitConverter.ToInt16(data, 0); } else if (type == typeof(ushort)) { return BitConverter.ToUInt16(data, 0); } else if (type == typeof(int)) { return BitConverter.ToInt32(data, 0); } else if (type == typeof(uint)) { return BitConverter.ToUInt32(data, 0); } else if (type == typeof(long)) { return BitConverter.ToInt64(data, 0); } else if (type == typeof(ulong)) { return BitConverter.ToUInt64(data, 0); } else if (type == typeof(float)) { return BitConverter.ToSingle(data, 0); } else if (type == typeof(double)) { return BitConverter.ToDouble(data, 0); } else { throw new Exception("类型不支持"); } } private byte[] ReadBytes(ref int bitStart, ushort length) { var start = GetByteStart(bitStart); var data = Data.Skip(start).Take(length).ToArray(); bitStart += length * 8; return data; } private bool ReadBit(ref int bitStart) { var start = GetByteStart(bitStart); var b = Data.Skip(start).First(); var bitIndex = GetBitIndex(bitStart); bitStart++; return b.GetBit(bitIndex); } #endregion 读取 #region 写入 public void Write(int bitStart, T value, int strLength, int arrLength) { Write(typeof(T), ref bitStart, value, strLength, arrLength); } private void Write(Type type, ref int bitStart, object value, int strLength, int arrLength) { if (type.IsArray) { var t = type.GetElementType(); if (t.IsArray) { throw new Exception("只支持一维数组"); } var arr = value as Array; if (arr.Length > arrLength) throw new Exception("数组长度超出"); foreach (var obj in arr) { Write(obj.GetType(), ref bitStart, obj, strLength, arrLength); } } else if (type == typeof(bool)) { WriteBit(ref bitStart, (bool)value); } else if (type == typeof(string)) { WriteString(ref bitStart, value.ToString(), strLength); } else if (type.IsEnum) { WriteEnum(ref bitStart, value); } else if (type.IsPrimitive) { var revers = Entity.PLC.TYPE == PLCType.西门子; WritePrimitive(ref bitStart, value, revers); } else throw new Exception("类型不支持"); } private void WriteString(ref int bitStart, string value, int strLen) { var data = Configs.StringEncoding.GetBytes(value); if (data.Length > strLen) throw new Exception("字符串长度超出"); if (Entity.PLC.TYPE == PLCType.西门子) { var title = new byte[] { (byte)strLen, (byte)data.Length }; data = title.Concat(data).ToArray(); } WriteBytes(ref bitStart, data); } private void WriteEnum(ref int bitStart, object value) { var etype = value.GetType(); var type = etype.GetEnumUnderlyingType(); var obj = Convert.ChangeType(value, type); var reverse = false; if (etype.GetCustomAttribute() == null) { reverse = Entity.PLC.TYPE == PLCType.西门子; } WritePrimitive(ref bitStart, obj, reverse); } private void WritePrimitive(ref int bitStart, object value, bool reverse) { var type = value.GetType(); byte[] data; if (type == typeof(char)) { data = BitConverter.GetBytes((char)value); } else if (type == typeof(byte)) { data = new byte[] { (byte)value }; } else if (type == typeof(short)) { data = BitConverter.GetBytes((short)value); } else if (type == typeof(ushort)) { data = BitConverter.GetBytes((ushort)value); } else if (type == typeof(int)) { data = BitConverter.GetBytes((int)value); } else if (type == typeof(uint)) { data = BitConverter.GetBytes((uint)value); } else if (type == typeof(long)) { data = BitConverter.GetBytes((long)value); } else if (type == typeof(ulong)) { data = BitConverter.GetBytes((ulong)value); } else { throw new Exception("类型不支持"); } if (reverse) data = data.Reverse().ToArray(); WriteBytes(ref bitStart, data); } private void WriteBytes(ref int bitStart, byte[] data) { lock (Entity.PLC) { var start = GetByteStart(bitStart); //DataServer.WriteBytes(Entity, start, data); Entity.PLC.Ex().Accessor.WriteBytes((ushort)Entity.NO, start, data); data.CopyTo(Data, start); bitStart += data.Length * 8; } } private void WriteBit(ref int bitStart, bool flag) { lock (Entity.PLC) { var start = GetByteStart(bitStart); var bitIndex = GetBitIndex(bitStart); var b = Data.Skip(start).First(); b = b.SetBit(bitIndex, flag); var data = new byte[] { b }; Entity.PLC.Ex().Accessor.WriteBytes((ushort)Entity.NO, (ushort)start, data); data.CopyTo(Data, start); bitStart += 1; } } #endregion 写入 } }