using Aitex.Common.Util; using Aitex.Core.RT.Device; using Aitex.Core.RT.IOCore; using Aitex.Core.Util; using MECF.Framework.Common.Device.Festo; using MECF.Framework.Common.Net; using MECF.Framework.Simulator.Core.Driver; using System; using System.Collections.Generic; using System.IO; using System.Net; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; namespace CyberX8_Simulator.Devices { public class FestoSocketSimulator : SocketDeviceSimulator { //Write Address private const ushort FESTO_DO_START_ADDRESS = 0x9C43;//FestoDO起始地址(40003) //Read Address private const ushort FESTO_DI_START_ADDRESS = 0xB153;//FestoDI起始地址(45395) //Register Count private const int FESTO_REGISTER_COUNT = 100; private IByteTransform byteTransform = new BigEndianByteTransformBase(); /// /// 数据(index - data) /// private short[] _festoOutputDataDic = new short[FESTO_REGISTER_COUNT]; /// /// 数据(DOName - index) /// private Dictionary _festoNameIndexDic = new Dictionary(); /// /// do 索引对象字典(key-地址索引-bit,value--do名称) /// private Dictionary _doNameDictionary = new Dictionary(); /// /// 构造函数 /// /// public FestoSocketSimulator(int port) : base(port) { for(int i = 0; i < FESTO_REGISTER_COUNT; i++) { _festoOutputDataDic[i] = 0x00; } string oldXmlPath = PathManager.GetCfgDir(); string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\FestoControllerCfg-Simulator.xml"; FestoControllerCfg cfg = CustomXmlSerializer.Deserialize(new FileInfo(newXmlPath)); foreach (FestoDeviceConfig config in cfg.FestoDeviceConfigs) { if(port == config.Port) { foreach (FestoDO item in config.FestoDoes) { _festoNameIndexDic[item.Name] = item; string str = $"{item.Address}-{item.Bit}"; _doNameDictionary[str] = item.Name; } } } } /// /// 解析信息 /// /// protected override void ProcessUnsplitMessage(byte[] data) { short flag = byteTransform.TransInt16(data, 0);//事务标识符 byte channel = data[6];//单元标识符 byte command = data[7];//功能码 if (command == 0x03)//读取 { ushort startAddress = byteTransform.TransUInt16(data, 8);//起始寄存器地址 short registerCount = byteTransform.TransInt16(data, 10);//寄存器数量 byte[] bytes = new byte[2 * registerCount];//读取2*registerCount Byte数据 if (startAddress >= FESTO_DI_START_ADDRESS) { for (int i = 0; i < registerCount; i++) { Array.Copy(byteTransform.GetBytes(_festoOutputDataDic[startAddress - FESTO_DI_START_ADDRESS + i]), 0, bytes, i * 2, 2); } OnWriteMessage(CreateReadResponse(flag, channel, command, registerCount, bytes)); } else { OnWriteMessage(CreateError(flag, channel, command, 0x8A)); } } else if(command == 0x06)//写入 { ushort startAddress = byteTransform.TransUInt16(data, 8);//起始寄存器地址 short value = byteTransform.TransInt16(data, 10);//写入的值(2 Byte) if(startAddress >= FESTO_DO_START_ADDRESS) { //通知相关数据变化 var result = DecodeDOData(startAddress, value); SimulatorCommManager.Instance.CheckDataChanged(result.Item1, result.Item2); //modbus起始地址n为数据,n+1为诊断数据,取地址n下的数据 _festoOutputDataDic[(startAddress - FESTO_DO_START_ADDRESS) * 2] = value; OnWriteMessage(CreateWriteResponse(flag, channel, command, startAddress, value)); } else { OnWriteMessage(CreateError(flag, channel, command, 0x8A)); } } else { OnWriteMessage(CreateError(flag, channel, command, 0x84)); } } /// /// 读回复 /// /// /// /// /// /// /// private byte[] CreateReadResponse(short flag, byte channel, byte command, short registerCount, byte[] values) { byte[] bytes = new byte[6 + 3 + values.Length]; Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2); bytes[2] = 0x00; bytes[3] = 0x00; short dataLength = (short)(3 + values.Length); Array.Copy(byteTransform.GetBytes(dataLength), 0, bytes, 4, 2); bytes[6] = channel; bytes[7] = command; bytes[8] = (byte)(2 * registerCount); Array.Copy(values, 0, bytes, 9, values.Length); return bytes; } /// /// 写回复 /// /// /// /// /// /// /// private byte[] CreateWriteResponse(short flag, byte channel, byte command, ushort startAddress, short value) { byte[] bytes = new byte[12]; Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2); bytes[2] = 0x00; bytes[3] = 0x00; bytes[4] = 0x00; bytes[5] = 0x06; bytes[6] = channel; bytes[7] = command; byte[] addressByt = byteTransform.GetBytes(startAddress); Array.Copy(addressByt, 0, bytes, 8, 2); byte[] valueByt = byteTransform.GetBytes(value); Array.Copy(valueByt, 0, bytes, 10, 2); return bytes; } /// /// 错误回复 /// /// /// /// /// /// private byte[] CreateError(short flag, byte channel, byte command, byte error) { byte[] bytes = new byte[9]; Array.Copy(byteTransform.GetBytes(flag), 0, bytes, 0, 2); bytes[2] = 0x00; bytes[3] = 0x00; bytes[4] = 0x00; bytes[5] = 0x03; bytes[6] = channel; bytes[7] = (byte)(command | 0x80); bytes[8] = error; return bytes; } /// /// 更新DI数据 /// /// /// public void UpdataDOBytes(string name, int value) { if (_festoNameIndexDic.ContainsKey(name)) { FestoDO festoDO = _festoNameIndexDic[name]; short byteValue = (short) (_festoOutputDataDic[(festoDO.Address - FESTO_DO_START_ADDRESS) * 2] & ~(1 << festoDO.Bit)); short tmp = (short)(value << festoDO.Bit); _festoOutputDataDic[(festoDO.Address - FESTO_DO_START_ADDRESS) * 2] = (short)(byteValue | tmp); } } /// /// 解析数据 /// /// /// /// private (string, bool) DecodeDOData(ushort address, short value) { int index = (address - FESTO_DO_START_ADDRESS) * 2; int bitNum = (int)Math.Log(_festoOutputDataDic[index] ^ value, 2); bool valueBool = (value & (1 << bitNum)) != 0 ? true : false; string str = $"{address}-{bitNum}"; return (_doNameDictionary[str], valueBool); } } }