| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 | using Aitex.Common.Util;using Aitex.Core.RT.Device;using Aitex.Core.RT.Log;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;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();        /// <summary>        /// 数据(index - data)        /// </summary>        private short[] _festoOutputDataDic = new short[FESTO_REGISTER_COUNT];        /// <summary>        /// 数据(DOName - FestoDO)        /// </summary>        public Dictionary<string, FestoDO> FestoNameIndexDic = new Dictionary<string, FestoDO>();        /// <summary>        /// 数据字典(DOName - value)        /// </summary>        public Dictionary<string, bool> FestoNameValueDic = new Dictionary<string, bool>();        /// <summary>        /// do 索引对象字典(key-地址索引-bit,value--do名称)        /// </summary>        private Dictionary<string, string> _doNameDictionary = new Dictionary<string, string>();        /// <summary>        /// 构造函数        /// </summary>        /// <param name="port"></param>        public FestoSocketSimulator(int port) : base(port)        {            InitData(port);                    }        /// <summary>        /// 解析信息        /// </summary>        /// <param name="data"></param>        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)                {                    //通知相关数据变化                    bool changeFlag = true;                    var result = DecodeDOData(startAddress, value, out changeFlag);                    if (changeFlag)                    {                                              SimulatorCommManager.Instance.CheckDataChanged(result.Item1, result.Item2, FestoNameIndexDic[result.Item1].Invert);                    }                                        //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));            }        }        /// <summary>        /// 读回复        /// </summary>        /// <param name="flag"></param>        /// <param name="channel"></param>        /// <param name="command"></param>        /// <param name="registerCount"></param>        /// <param name="values"></param>        /// <returns></returns>        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;        }        /// <summary>        /// 写回复        /// </summary>        /// <param name="flag"></param>        /// <param name="channel"></param>        /// <param name="command"></param>        /// <param name="startAddress"></param>        /// <param name="value"></param>        /// <returns></returns>        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;        }                /// <summary>        /// 错误回复        /// </summary>        /// <param name="flag"></param>        /// <param name="channel"></param>        /// <param name="command"></param>        /// <param name="error"></param>        /// <returns></returns>        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;        }        /// <summary>        /// 更新DI数据        /// </summary>        /// <param name="name"></param>        /// <param name="value"></param>        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);            }        }        /// <summary>        /// 解析数据        /// </summary>        /// <param name="address"></param>        /// <param name="value"></param>        /// <returns></returns>        private (string, bool) DecodeDOData(ushort address, short value, out bool flag, bool check = false)        {            flag = true;            int index = (address - FESTO_DO_START_ADDRESS) * 2;            if (!check &&_festoOutputDataDic[index] == value)             {                flag = false;                return ("", false);            }             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);        }        /// <summary>        /// 获取当前DO数据        /// </summary>        /// <param name="doName"></param>        /// <returns></returns>        public int GetDOData(string doName)        {            FestoDO data = FestoNameIndexDic[doName];            int result = 0;            result = (_festoOutputDataDic[(data.Address - FESTO_DO_START_ADDRESS) * 2] & (short)(1 << data.Bit)) == 0 ? 0 : 1;            return result;        }        /// <summary>        /// 初始化        /// </summary>        private void InitData(int port)        {            //初始化数据            for (int i = 0; i < FESTO_REGISTER_COUNT; i++)            {                _festoOutputDataDic[i] = 0x00;            }            //加载对应配置文件 FestoControllerCfg-Simulator.xml            try            {                string oldXmlPath = PathManager.GetCfgDir();                string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\FestoControllerCfg-Simulator.xml";                FestoControllerCfg cfg = CustomXmlSerializer.Deserialize<FestoControllerCfg>(new FileInfo(newXmlPath));                if (cfg != null)                {                    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;                            }                        }                    }                }            }            catch            {                LOG.WriteLog(eEvent.ERR_FESTO, "Festo", "Load festo FestoControllerCfg-Simulator.xml failed");            }                                }    }}
 |