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);
}
}
}