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