using Aitex.Common.Util;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using MECF.Framework.Common.Beckhoff.AxisProvider;
using MECF.Framework.Common.Device.Galil;
using MECF.Framework.Common.Net;
using MECF.Framework.Common.Simulator;
using MECF.Framework.Simulator.Core.Driver;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace CyberX8_Simulator.Devices
{
public class GalilSocketSimulator : SocketDeviceSimulator
{
#region 常量
//最大运动轴数量(abcdefg)
private const int MAX_AXIS_NUM = 8;
//GalilControllerData最大数据长度
private const int MAX_CONTROL_DATA_LENGTH_21 = 264;
private const int MAX_CONTROL_DATA_LENGTH_40 = 366;
//GalilAxisData最大数据长度
private const int MAX_AXIS_DATA_LENGTH_21 = 28;
private const int MAX_AXIS_DATA_LENGTH_40 = 36;
//GalilType
private const string GALIL_21 = "Galil21";
private const string GALIL_40 = "Galil40";
private const string TARGET_VELOCITY = "TargetVelocity";
private const string TARGET_ACCEL = "TargetAcceleration";
private const string TARGET_DECEL = "TargetDeceleration";
private const string TARGET_POSITION = "TargetPosition";
private const string SWITCH_SIGNAL = "SwitchSignal";
private const string ACTUAL_POSITION = "ActualPosition";
private const string AUXILIARY_POSITION = "AuxiliaryPosition";
private const string HOMING_SIGNAL = "HomingSignal";
private const string MOTION_SIGNAL = "MotionSignal";
private const string STOP_SIGNAL = "StopSignal";
#endregion
#region 内部变量
private IByteTransform byteTransform = new BigEndianByteTransformBase();
///
/// Galil数据
///
private GalilControllerData _galilControlData = new GalilControllerData();
///
/// Axis名称字典(key:axisName, value:index)
///
private Dictionary _axisNameIndexDic = new Dictionary();
///
/// Axis名称列表(index - axisName)
///
private string[] _nameAxisList = new string[MAX_AXIS_NUM];
///
/// ModuleName
///
///
private string _moduleName;
///
/// Galil Type
///
private string _galilType;
///
/// GalilControllerData数据长度
///
private int _controlDataLength;
///
/// GalilAxisDatas数据长度
///
private int _axisDataLength;
///
/// MotorPosition比例系数字典(index - motorPositionRate)
///
private Dictionary _motorPositionRateDic = new Dictionary();
///
/// Key:dataName - Value:GalilDI
///
public Dictionary InputDataNameDIDic = new Dictionary();
#endregion
///
/// 构造函数
///
///
public GalilSocketSimulator(int port) :base(port)
{
InitData(port);
}
///
/// 解析信息
///
///
protected override void ProcessUnsplitMessage(byte[] data)
{
string cmdStr = ASCIIEncoding.ASCII.GetString(data);
if (CheckCmdValid(cmdStr))
{
var cmdOperation = AnalyseCommand(cmdStr);
byte[] response;
if(cmdOperation.Item1 == "QR")
{
//Read
response = CreateReadResponse(_galilControlData);
}
else
{
//Write
SetOperation(cmdOperation.Item1, cmdOperation.Item2, cmdOperation.Item3);
response = CreateWriteResponse();
}
OnWriteMessage(response);
}
else
{
OnWriteMessage(CreateError());
}
}
///
/// 读回复
///
///
///
///
///
///
///
private byte[] CreateReadResponse(GalilControllerData data)
{
//数据头(4 bytes)
int headLength = 4;
byte[] result = new byte[headLength + _controlDataLength];
result[0] = 0x00;
result[1] = 0x00;
short dataLength = (short)(headLength + _controlDataLength);
Array.Copy(byteTransform.GetBytes(dataLength), 0, result, 2, 2);
//数据体(MAX_CONTROL_DATA_LENGTH bytes)
switch (_galilType)
{
case GALIL_21:
Array.Copy(CodeControlData21(data), 0, result, 4, MAX_CONTROL_DATA_LENGTH_21);
break;
case GALIL_40:
Array.Copy(CodeControlData40(data), 0, result, 4, MAX_CONTROL_DATA_LENGTH_40);
break;
default:
break;
}
return result;
}
///
/// 写回复
///
///
///
///
///
///
///
private byte[] CreateWriteResponse()
{
//数据头(1 bytes)
int headLength = 1;
byte[] result = new byte[headLength];
result[0] = 0x3A;
return result;
}
///
/// 错误回复
///
///
///
///
///
///
private byte[] CreateError()
{
int headLength = 1;
byte[] result = new byte[headLength];
//Command not valid in program
result[0] = 0x03;
return result;
}
///
/// 初始化
///
private void InitData(int port)
{
//初始化AxisData(最大MAX_AXIS_NUM个axis)
_galilControlData.GalilAxisDatas = new List();
for (int i = 0; i < MAX_AXIS_NUM; i++)
{
_galilControlData.GalilAxisDatas.Add(new GalilAxisData());
_galilControlData.GalilAxisDatas[i].Status = 0x00;
}
_galilControlData.Inputs = new byte[10];
_galilControlData.Outputs = new byte[10];
//电机数据更新事件
MotorSimulator.Instance.OnUpdateMotionDatasChanged += UpdateRealTimeMotionData;
MotorSimulator.Instance.OnUpdateInputDatasChanged += UpdateInputData;
//加载GalilControllerCfg-Simulator.xml
try
{
string oldXmlPath = PathManager.GetCfgDir();
string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\GalilControllerCfg-Simulator.xml";
GalilControllerCfg cfg = CustomXmlSerializer.Deserialize(new FileInfo(newXmlPath));
if(cfg != null)
{
foreach (GalilDeviceConfig config in cfg.GalilDeviceConfigs)
{
if (port == config.Port)
{
_moduleName = config.Module;
_galilType = config.GalilType;
foreach (GalilAxisConfig item in config.GalilAxises)
{
_axisNameIndexDic[$"{config.Module}.{item.Name}"] = item.Index;
_nameAxisList[item.Index] = $"{config.Module}.{item.Name}";
}
if (config.GalilDigIn != null && config.GalilDigIn.DIs.Count != 0)
{
foreach (var items in config.GalilDigIn.DIs)
{
InputDataNameDIDic[items.Name] = items;
}
}
}
}
}
}
catch
{
LOG.WriteLog(eEvent.ERR_GALIL, "Galil", "Load galil GalilControllerCfg-Simulator.xml failed");
}
//加载AxisProviderCfg.xml
try
{
string oldXmlPath = PathManager.GetCfgDir();
string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\AxisProviderCfg.xml";
BeckhoffAxisProviderCfg axisProviderCfg = CustomXmlSerializer.Deserialize(new FileInfo(newXmlPath));
if (axisProviderCfg != null)
{
foreach (BeckhoffProviderAxis item in axisProviderCfg.Axes)
{
for (int i = 0; i < MAX_AXIS_NUM; i++)
{
if (_nameAxisList[i] == item.Name)
{
_motorPositionRateDic[item.Name] = item.MotorPositionRate;
}
}
}
}
}
catch
{
LOG.WriteLog(eEvent.ERR_AXIS, "axisProvider", "Load AxisProviderCfg.xml failed");
}
//初始化对应Galiltype数据
if (_galilType == GALIL_40)
{
_controlDataLength = MAX_CONTROL_DATA_LENGTH_40;
_axisDataLength = MAX_AXIS_DATA_LENGTH_40;
_galilControlData.SBlocks = new byte[10];
_galilControlData.TBlocks = new byte[10];
}
else
{
_controlDataLength = MAX_CONTROL_DATA_LENGTH_21;
_axisDataLength = MAX_AXIS_DATA_LENGTH_21;
_galilControlData.SBlocks = new byte[8];
_galilControlData.TBlocks = new byte[8];
}
}
#region Galil编码
///
/// GalilControllerData编码(Galil21)
///
///
private byte[] CodeControlData21(GalilControllerData ctrlData)
{
byte[] result = new byte[MAX_CONTROL_DATA_LENGTH_21];
int index = 0;
//Sample(2 bytes)
Array.Copy(BitConverter.GetBytes(ctrlData.Sample), 0, result, index, 2);
index += 2;
//Inputs(1*10 bytes)
Array.Copy(ctrlData.Inputs, 0, result, index, 10);
index += 10;
//Outputs(1*10 bytes)
Array.Copy(ctrlData.Outputs, 0, result, index, 10);
index += 10;
//Error Code(1 bytes)
result[13] = ctrlData.ErrorCode;
index++;
//General Status(1 bytes)
result[14] = ctrlData.Status;
index++;
//S Block(2+2+4=8 bytes)
Array.Copy(ctrlData.SBlocks, 0, result, 15, 8);
index += 8;
//T Block(2+2+4=8 bytes)
Array.Copy(ctrlData.TBlocks, 0, result, 23, 8);
index += 8;
//Axis Datas(28 * 8 bytes)
for (int i = 0; i < MAX_AXIS_NUM; i++)
{
Array.Copy(CodeAxisData21(ctrlData.GalilAxisDatas[i]), 0, result, index, MAX_AXIS_DATA_LENGTH_21);
index += MAX_AXIS_DATA_LENGTH_21;
}
return result;
}
///
/// GalilAxisData编码(Galil21)
///
///
///
private byte[] CodeAxisData21(GalilAxisData axisData)
{
byte[] result = new byte[MAX_AXIS_DATA_LENGTH_21];
int index = 0;
//Status(2 bytes)
Array.Copy(byteTransform.GetBytes(axisData.Status), 0, result, index, 2);
index += 2;
//Switches(1 bytes)
result[index] = axisData.Switches;
index++;
//Stop Code(1 bytes)
result[index] = axisData.StopCode;
index++;
//Reference Position(4 bytes)
Array.Copy(BitConverter.GetBytes(axisData.ReferencePosition), 0, result, index, 4);
index += 4;
//Motor Position(4 bytes)
Array.Copy(BitConverter.GetBytes(axisData.MotorPosition), 0, result, index, 4);
index += 4;
//Position Error
Array.Copy(BitConverter.GetBytes(axisData.PositionError), 0, result, index, 4);
index += 4;
//Auxiliary Position
Array.Copy(BitConverter.GetBytes(axisData.AuxiliaryPosition), 0, result, index, 4);
index += 4;
//Velocity
Array.Copy(BitConverter.GetBytes(axisData.Velocity), 0, result, index, 4);
index += 4;
//Torque
Array.Copy(BitConverter.GetBytes(axisData.Torque), 0, result, index, 2);
index += 2;
//Analog
Array.Copy(BitConverter.GetBytes(axisData.Res), 0, result, index, 2);
return result;
}
///
/// GalilControllerData编码(Galil40)
///
///
private byte[] CodeControlData40(GalilControllerData ctrlData)
{
byte[] result = new byte[MAX_CONTROL_DATA_LENGTH_40];
int index = 0;
//Sample(2 bytes)
Array.Copy(BitConverter.GetBytes(ctrlData.Sample), 0, result, index, 2);
index += 2;
//Inputs(1*10 bytes)
Array.Copy(ctrlData.Inputs, 0, result, index, 10);
index += 10;
//Outputs(1*10 bytes)
Array.Copy(ctrlData.Outputs, 0, result, index, 10);
index += 10;
//reservers
byte[] reservers = new byte[16];
Array.Copy(reservers, 0, result, index, 16);
index += 16;
//ethernet
byte[] ethernet = new byte[8];
Array.Copy(ethernet, 0, result, index, 8);
index += 8;
//ethernet
//Error Code(1 bytes)
result[13] = ctrlData.ErrorCode;
index++;
//General Status(1 bytes)
result[14] = ctrlData.Status;
index++;
//ampliferStatus
byte[] ampliferStatus = new byte[4];
Array.Copy(ampliferStatus, 0, result, index, 4);
index += 4;
//counterModel
byte[] counterModel = new byte[6];
Array.Copy(counterModel, 0, result, index, 6);
index += 6;
//S Block(10 bytes)
Array.Copy(ctrlData.SBlocks, 0, result, index, 10);
index += 10;
//T Block(10 bytes)
Array.Copy(ctrlData.TBlocks, 0, result, index, 10);
index += 10;
//Axis Datas(36 * 8 bytes)
for (int i = 0; i < MAX_AXIS_NUM; i++)
{
Array.Copy(CodeAxisData40(ctrlData.GalilAxisDatas[i]), 0, result, index, MAX_AXIS_DATA_LENGTH_40);
index += MAX_AXIS_DATA_LENGTH_40;
}
return result;
}
///
/// GalilAxisData编码(Galil40)
///
///
///
private byte[] CodeAxisData40(GalilAxisData axisData)
{
byte[] result = new byte[MAX_AXIS_DATA_LENGTH_40];
int index = 0;
//Status(2 bytes)
Array.Copy(byteTransform.GetBytes(axisData.Status), 0, result, index, 2);
index += 2;
//Switches(1 bytes)
result[index] = axisData.Switches;
index++;
//Stop Code(1 bytes)
result[index] = axisData.StopCode;
index++;
//Reference Position(4 bytes)
Array.Copy(BitConverter.GetBytes(axisData.ReferencePosition), 0, result, index, 4);
index += 4;
//Motor Position(4 bytes)
Array.Copy(BitConverter.GetBytes(axisData.MotorPosition), 0, result, index, 4);
index += 4;
//Position Error
Array.Copy(BitConverter.GetBytes(axisData.PositionError), 0, result, index, 4);
index += 4;
//Auxiliary Position
Array.Copy(BitConverter.GetBytes(axisData.AuxiliaryPosition), 0, result, index, 4);
index += 4;
//Velocity
Array.Copy(BitConverter.GetBytes(axisData.Velocity), 0, result, index, 4);
index += 4;
//Torque
Array.Copy(BitConverter.GetBytes(axisData.Torque), 0, result, index, 4);
index += 4;
//Analog
Array.Copy(BitConverter.GetBytes(axisData.Res), 0, result, index, 2);
index += 2;
byte hallInput = 0x00;
result[index] = hallInput;
index ++;
byte reserved = 0x00;
result[index] = reserved;
index ++;
byte[] userVariables = new byte[4];
Array.Copy(userVariables, 0, result, index, 4);
return result;
}
#endregion
///
/// 解析指令(操作符, 运动轴, 操作数)
///
///
///
private (string, char, int) AnalyseCommand(string cmdStr)
{
var result = ("", ' ', -1);
//操作符
result.Item1 = cmdStr.Substring(0, 2);
//运动轴
if (cmdStr.Length >= 4)
{
result.Item2 = Convert.ToChar(cmdStr.Substring(2, 1));
}
//操作数
if (cmdStr.Length >= 5 && int.TryParse(cmdStr.Substring(4, cmdStr.Length - 5), out int tmp))
{
result.Item3 = tmp;
}
return result;
}
///
/// CMD校验
///
///
private bool CheckCmdValid(string cmdStr)
{
//长度
if(cmdStr.Length < 3) return false;
//;结尾
if (!cmdStr.EndsWith(";")) return false;
//第1位为A~Z
if (cmdStr[0] < 'A' || cmdStr[0] > 'Z') return false;
//第2位为A~Z
if (cmdStr[1] < 'A' || cmdStr[1] > 'Z') return false;
if(cmdStr[0] == 'C'&& cmdStr[1] == 'N')
{
return true;
}
if (cmdStr.Length >= 4)
{
//axis名称为A~H
if (cmdStr[2] < 'A' || cmdStr[2] > 'H') return false;
//=
if(cmdStr.Length > 4 && !cmdStr.Contains("=")) return false;
}
return true;
}
///
/// 设置操作
///
///
///
///
///
private bool SetOperation(string cmd, char axis, int value)
{
switch (cmd)
{
case "SH"://上电
SwitchMotor(axis, true);
break;
case "MO"://下电
SwitchMotor(axis, false);
break;
case "PR"://相对位置
SetTargetRelativePosition(axis, value);
break;
case "PA"://绝对位置
SetTargetAbsolutePosition(axis, value);
break;
case "SP"://速度
SetSpeed(axis, value);
break;
case "AC"://加速度
SetAcceleration(axis, value);
break;
case "DC"://减速度
SetDeceleration(axis, value);
break;
case "ST"://停止
ControlMotion(axis, false);
break;
case "BG"://启动
ControlMotion(axis, true);
break;
case "HM"://回零
Home(axis);
break;
case "DP"://设定motor position
SetMotorPosition(axis, value);
break;
case "DE"://设定auxiliary position
SetAuxiliaryPosition(axis, value);
break;
case "CN":
break;
default:
break;
}
return true;
}
///
/// 实时更新电机数据
///
///
private void UpdateRealTimeMotionData(Dictionary datasDic)
{
foreach(var dataItem in datasDic)
{
if (_axisNameIndexDic.ContainsKey(dataItem.Key))
{
UpdateAxisData(_axisNameIndexDic[dataItem.Key], dataItem.Value);
}
}
}
///
/// 更新Galil Input datas
///
private void UpdateInputData(string module, string VariableName, bool value)
{
if(_moduleName == module && InputDataNameDIDic.ContainsKey(VariableName))
{
int tmp = InputDataNameDIDic[VariableName].Invert ? (!value ? 1 : 0) : (value ? 1 : 0);
_galilControlData.Inputs[InputDataNameDIDic[VariableName].Address] = (byte)(tmp << InputDataNameDIDic[VariableName].Bit);
}
}
///
/// 更新对应Axis数据
///
///
private void UpdateAxisData(int index, SimulatorMotionData data)
{
_galilControlData.GalilAxisDatas[index].Velocity = data.ActualVelocity;
_galilControlData.GalilAxisDatas[index].MotorPosition = (int)(data.ActualPosition / _motorPositionRateDic[_nameAxisList[index]]);
_galilControlData.GalilAxisDatas[index].ReferencePosition = data.TargetPosition;
_galilControlData.GalilAxisDatas[index].Torque = data.ActualTorque;
_galilControlData.GalilAxisDatas[index].StopCode = data.StopCode;
}
///
/// 模拟器UI更新inputs数据
///
///
///
public void UpdateInputByte(string name, int value)
{
if (InputDataNameDIDic.ContainsKey(name))
{
GalilDI galilDI = InputDataNameDIDic[name];
short byteValue = (short)(_galilControlData.Inputs[galilDI.Address] & ~(1 << galilDI.Bit));
short tmp = (short)(value << galilDI.Bit);
_galilControlData.Inputs[galilDI.Address] = (byte)(byteValue | tmp);
}
}
///
/// 模拟器获取inputs数据
///
///
public int GetInputData(string name)
{
int result = 0;
if (!InputDataNameDIDic.ContainsKey(name)) return 0;
GalilDI galilDI = InputDataNameDIDic[name];
int tmp = _galilControlData.Inputs[galilDI.Address] & (1 << galilDI.Bit);
result = (tmp == (1 << galilDI.Bit)) ? 1 : 0;
return result;
}
#region AxisOperation
///
/// 开/关电机
///
///
///
private void SwitchMotor(char axis, bool flag)
{
byte[] data = byteTransform.GetBytes(_galilControlData.GalilAxisDatas[axis - 'A'].Status);
data[0] &= 0xFE;
data[0] |= (byte)(flag ? 0x00 : 0x01);
_galilControlData.GalilAxisDatas[axis - 'A'].Status = byteTransform.TransUInt16(data, 0);
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], SWITCH_SIGNAL, flag);
}
///
/// 设置速度
///
private void SetSpeed(char axis, int value)
{
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], TARGET_VELOCITY, value);
}
///
/// 设置加速度
///
private void SetAcceleration(char axis, int value)
{
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], TARGET_ACCEL, value);
}
///
/// 设置减速度
///
private void SetDeceleration(char axis, int value)
{
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], TARGET_DECEL, value);
}
///
/// 设置目标绝对位置(设定位置)
///
private void SetTargetAbsolutePosition(char axis, int value)
{
_galilControlData.GalilAxisDatas[axis - 'A'].ReferencePosition = value;
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], TARGET_POSITION, value);
}
///
/// 设置目标相对位置(设定位置)
///
private void SetTargetRelativePosition(char axis, int value)
{
_galilControlData.GalilAxisDatas[axis - 'A'].ReferencePosition = _galilControlData.GalilAxisDatas[axis - 'A'].MotorPosition + value;
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], TARGET_POSITION, _galilControlData.GalilAxisDatas[axis - 'A'].ReferencePosition);
}
///
/// 设置 Motor Position(实际位置)
///
///
///
private void SetMotorPosition(char axis, int value)
{
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], ACTUAL_POSITION, value);
}
///
/// 设置 Auxiliary Position
///
///
///
private void SetAuxiliaryPosition(char axis, int value)
{
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], AUXILIARY_POSITION, value);
}
///
/// 控制运动
///
private void ControlMotion(char axis, bool value)
{
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], value ? MOTION_SIGNAL : STOP_SIGNAL, value);
}
///
/// 电机回零
///
///
private void Home(char axis)
{
MotorSimulator.Instance.SetMotionData(_nameAxisList[axis - 'A'], HOMING_SIGNAL, true);
}
#endregion
}
}