//调用前应对地址数组排序(是否加锁?),先一整块PDU读取到 缓存中,然后再逐个从缓存中 读取到各变量地址中 public static ItemData <Storage>[] PLCReadMultiple(this IPLCDriver plc, ICache cache, DeviceAddress[] addrsArr) { if (addrsArr == null || cache == null || addrsArr.Length == 0) { return(null); } int len = addrsArr.Length; //读取的 变量地址的个数 ItemData <Storage>[] items = new ItemData <Storage> [len]; //需要填充的列表 int offset = 0; long now = DateTime.Now.ToFileTime(); List <PDUArea> areas = cache.AssignFromPDU(plc.PDU, addrsArr); foreach (PDUArea area in areas) { byte[] rcvBytes = plc.ReadBytes(area.Start, (ushort)area.Len); Buffer.BlockCopy(rcvBytes, 0, cache.Cache, offset, rcvBytes.Length); offset += rcvBytes.Length / cache.ByteCount; } for (int i = 0; i < len; i++) { switch (addrsArr[i].VarType) { case DataType.BOOL: items[i].Value.Boolean = cache.ReadBit(addrsArr[i]).Value; break; case DataType.BYTE: items[i].Value.Byte = cache.ReadByte(addrsArr[i]).Value; break; case DataType.WORD: items[i].Value.Word = cache.ReadUInt16(addrsArr[i]).Value; break; case DataType.SHORT: items[i].Value.Int16 = cache.ReadInt16(addrsArr[i]).Value; break; case DataType.DWORD: items[i].Value.DWord = cache.ReadUInt32(addrsArr[i]).Value; break; case DataType.INT: items[i].Value.Int32 = cache.ReadInt32(addrsArr[i]).Value; break; case DataType.FLOAT: items[i].Value.Single = cache.ReadFloat(addrsArr[i]).Value; break; case DataType.STR: var item = cache.ReadString(addrsArr[i], addrsArr[i].DataSize); break; } items[i].Quality = QUALITIES.QUALITY_GOOD; items[i].TimeStamp = now; } return(items); }
public static int PLCWriteMultiple(this IPLCDriver plc, ICache cache, DeviceAddress[] addrArr, object[] buffer, int limit) { if (cache == null || addrArr == null || buffer == null || addrArr.Length != buffer.Length) { return(-1); } if (addrArr.Length == 1) { return(plc.WriteValue(addrArr[0], buffer[0])); } lock (plc) //不锁定会有并发冲突问题;锁定也不能保障绝对安全,如有人现场操作会导致数据刷新 { List <PDUArea> areas = cache.AssignFromPDU(plc.PDU, addrArr); int offset = 0; foreach (PDUArea area in areas) { byte[] rcvBytes = plc.ReadBytes(area.Start, (ushort)area.Len); if (rcvBytes == null) { return(-1); } Buffer.BlockCopy(rcvBytes, 0, cache.Cache, offset, rcvBytes.Length); offset += rcvBytes.Length / cache.ByteCount; } DeviceAddress start = addrArr[0]; int startIndex = 0; int endIndex = 0; while (endIndex < addrArr.Length) { if (start.Area != addrArr[endIndex].Area || start.DBNumber != addrArr[endIndex].DBNumber || endIndex - startIndex >= limit) { for (int i = startIndex; i < endIndex; i++) { cache.WriteValue(addrArr[i], buffer[i]); } int c1 = start.CacheIndex; int c2 = addrArr[endIndex - 1].CacheIndex; byte[] bytes = new byte[cache.ByteCount * (c2 - c1 + 1)]; Buffer.BlockCopy(cache.Cache, c1, bytes, 0, bytes.Length); if (plc.WriteBytes(start, bytes) < 0) { return(-1); } start = addrArr[endIndex]; startIndex = endIndex; } endIndex++; } } return(0); }
protected virtual int Poll() { if (_plcReader.IsClosed) { return(-1); } byte[] cache = (byte[])_cacheReader.Cache; int offset = 0; foreach (PDUArea area in _rangeList) { byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据 if (rcvBytes == null) { //_plcReader.Connect(); return(-1); } else { int index = area.StartIndex;//index指向_items中的Tag元数据 int count = index + area.Count; while (index < count) { DeviceAddress addr = _items[index].Address; int iByte = addr.CacheIndex; int iByte1 = iByte - offset; if (addr.VarType == DataType.BOOL) { int tmp = rcvBytes[iByte1] ^ cache[iByte]; DeviceAddress next = addr; if (tmp != 0) { while (addr.Start == next.Start) { if ((tmp & (1 << next.Bit)) > 0) { _changedList.Add(index); } if (++index < count) { next = _items[index].Address; } else { break; } } } else { while (addr.Start == next.Start && ++index < count) { next = _items[index].Address; } } } else { ushort size = addr.DataSize; for (int i = 0; i < size; i++) { if (rcvBytes[iByte1 + i] != cache[iByte + i]) { _changedList.Add(index); break; } } index++; } } for (int j = 0; j < rcvBytes.Length; j++) { cache[j + offset] = rcvBytes[j];//将PLC读取的数据写入到CacheReader中 } } offset += rcvBytes.Length; } return(1); }
/// <summary> /// 主通信流程:Step 2:从通信模块中获取数据,并记录变化量地址 /// </summary> protected virtual void Poll() { if (_plcReader.IsClosed) { return; } byte[] cache = (byte[])_cacheReader.Cache; //这个是缓存里面的数据,用来和新取得数据进行对比 int offset = 0; //收到的新的字节中的偏移量 foreach (PDUArea area in _rangeList) { byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//逐一从PLC读取数据读取指定的长度(对于我们程序就是UDP从网络端口读取的数据),对于我们的程序就是固定一个长度就好 if (rcvBytes == null) { //_plcReader.Connect(); continue; } else { int index = area.StartIndex; //index指向_items中的Tag元数据 index 是Itag的索引 int count = index + area.Count; //count 是总共的Itag 列表的个数,Count 指单次读取的字节中所包含的 Itag个数 while (index < count) { DeviceAddress addr = _items[index].Address; //根据在Itag里面的索引,得到内存中的地址 int iByte = addr.CacheIndex; //在内存中的字节索引地址 int iByte1 = iByte - offset; //在内存中,因为前一个PDUArea块的存在,偏移量,所以到读取的新的字节数组中,要求减去这个偏移量 if (addr.VarType == DataType.BOOL) { int tmp = rcvBytes[iByte1] ^ cache[iByte]; //对比一下内存里面的值,看有没有发生变化,有的话就需要更新,保留异或位 DeviceAddress next = addr; if (tmp != 0) //看整个字节里面的8个位有没有发生变化 { while (addr.Start == next.Start) //下面while循环比较同一个字节里面不同的位,是否都发生了变化,因为起始地址都是按字节计算的 { if ((tmp & (1 << next.Bit)) > 0) { _changedList.Add(index); //tmp里面记录了所有发生变化的位,后面的Itag要是起始地址相同,说明是一个字节里面不同的位有变化 } if (++index < count) { next = _items[index].Address; } else { break; } } } else { while (addr.Start == next.Start && ++index < count) { next = _items[index].Address; } } } else { ushort size = addr.DataSize;//把单个Itag字节长度取出来,一个一个字节进行对比 for (int i = 0; i < size; i++) { if (iByte1 + i < rcvBytes.Length && rcvBytes[iByte1 + i] != cache[iByte + i])//只要发现长度size当中有任何变化的值,就是值有变化 { _changedList.Add(index); break; } } index++; } } for (int j = 0; j < rcvBytes.Length; j++) { cache[j + offset] = rcvBytes[j];//将PLC读取的数据写入到CacheReader中,所有都更新到内存中,但只推送那些变化的值 } } offset += rcvBytes.Length; } }
protected virtual unsafe void Poll() { short[] cache = (short[])_cacheReader.Cache; int k = 0; foreach (PDUArea area in _rangeList) { byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据 if (rcvBytes == null) { k += (area.Len + 1) / 2; continue; } else { int len = rcvBytes.Length / 2; fixed(byte *p1 = rcvBytes) { short *prcv = (short *)p1; int index = area.StartIndex;//index指向_items中的Tag元数据 int count = index + area.Count; while (index < count) { DeviceAddress addr = _items[index].Address; int iShort = addr.CacheIndex; int iShort1 = iShort - k; if (addr.VarType == DataType.BOOL) { int tmp = prcv[iShort1] ^ cache[iShort]; DeviceAddress next = addr; if (tmp != 0) { while (addr.Start == next.Start) { if ((tmp & (1 << next.Bit)) > 0) { _changedList.Add(index); } if (++index < count) { next = _items[index].Address; } else { break; } } } else { while (addr.Start == next.Start && ++index < count) { next = _items[index].Address; } } } else { if (addr.ByteOrder.HasFlag(ByteOrder.BigEndian)) { for (int i = 0; i < addr.DataSize / 2; i++) { prcv[iShort1 + i] = IPAddress.HostToNetworkOrder(prcv[iShort1 + i]); } } if (addr.DataSize <= 2) { if (prcv[iShort1] != cache[iShort]) { _changedList.Add(index); } } else { int size = addr.DataSize / 2; for (int i = 0; i < size; i++) { if (prcv[iShort1 + i] != cache[iShort + i]) { _changedList.Add(index); break; } } } index++; } } short[] prcvShorts = new short[len]; for (int i = 0; i < len; i++) { prcvShorts[i] = prcv[i]; } //改成Array.Copy 由于线程安全的问题 Array.Copy(prcvShorts, 0, cache, k, len); /* * for (int j = 0; j < len; j++) * { * cache[j + offset] = prcv[j]; * }//将PLC读取的数据写入到CacheReader中 */ } k += len; } } }