using Aitex.Common.Util; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Routine; using Aitex.Core.Util; using CyberX8_Core; using MECF.Framework.Common.CommonData.PUF; using MECF.Framework.Common.Device.Festo; 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; using Xceed.Wpf.Toolkit.Panels; 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 = 264; //GalilAxisData最大数据长度 private const int MAX_AXIS_DATA_LENGTH = 28; #endregion #region 内部变量 private IByteTransform byteTransform = new BigEndianByteTransformBase(); /// /// Galil数据 /// private GalilControllerData _galilControlData = new GalilControllerData(); /// /// Axis名称字典(key:axisName, value:index) /// private Dictionary _axisNameIndexDic = new Dictionary(); /// /// ModuleName /// /// private string _moduleName; #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 + MAX_CONTROL_DATA_LENGTH]; result[0] = 0x00; result[1] = 0x00; short dataLength = (short)(headLength + MAX_CONTROL_DATA_LENGTH); Array.Copy(byteTransform.GetBytes(dataLength), 0, result, 2, 2); //数据体(MAX_CONTROL_DATA_LENGTH bytes) Array.Copy(CodeControlData(data), 0, result, 4, MAX_CONTROL_DATA_LENGTH); 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 = 0x01; } _galilControlData.Inputs = new byte[10]; _galilControlData.Outputs = new byte[10]; _galilControlData.SBlocks = new byte[8]; _galilControlData.TBlocks = new byte[8]; //电机数据更新事件 MotorSimulator.Instance.OnUpdateVariableValueChanged += UpdataRealTimeMotionData; //加载对应配置文件 GalilControllerCfg-Simulator.xml string oldXmlPath = PathManager.GetCfgDir(); string newXmlPath = oldXmlPath.Replace("CyberX8_Simulator", "CyberX8_RT") + "Devices\\GalilControllerCfg-Simulator.xml"; GalilControllerCfg cfg = CustomXmlSerializer.Deserialize(new FileInfo(newXmlPath)); foreach (GalilDeviceConfig config in cfg.GalilDeviceConfigs) { if (port == config.Port) { _moduleName = config.Module; foreach (GalilAxisConfig item in config.GalilAxises) { _axisNameIndexDic[$"{config.Module}.{item.Name}"] = item.Index; } } } } /// /// GalilControllerData编码 /// /// private byte[] CodeControlData(GalilControllerData ctrlData) { byte[] result = new byte[MAX_CONTROL_DATA_LENGTH]; int index = 0; //Sample(2 bytes) Array.Copy(byteTransform.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(CodeAxisData(ctrlData.GalilAxisDatas[i]), 0, result, index, MAX_AXIS_DATA_LENGTH); index += MAX_AXIS_DATA_LENGTH; } return result; } /// /// GalilAxisData编码 /// /// /// private byte[] CodeAxisData(GalilAxisData axisData) { byte[] result = new byte[MAX_AXIS_DATA_LENGTH]; 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(byteTransform.GetBytes(axisData.ReferencePosition), 0, result, index, 4); index += 4; //Motor Position(4 bytes) Array.Copy(byteTransform.GetBytes(axisData.MotorPosition), 0, result, index, 4); index += 4; //Position Error Array.Copy(byteTransform.GetBytes(axisData.PositionError), 0, result, index, 4); index += 4; //Auxiliary Position Array.Copy(byteTransform.GetBytes(axisData.AuxiliaryPosition), 0, result, index, 4); index += 4; //Velocity Array.Copy(byteTransform.GetBytes(axisData.Velocity), 0, result, index, 4); index += 4; //Torque Array.Copy(byteTransform.GetBytes(axisData.Torque), 0, result, index, 2); index += 2; //Analog Array.Copy(byteTransform.GetBytes(axisData.Res), 0, result, index, 2); return result; } /// /// 解析指令(操作符, 运动轴, 操作数) /// /// /// 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.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": break; case "AC": break; case "DC": break; case "ST": break; case "BG": break; case "HM": break; case "DP": break; case "DE": break; default: break; } return true; } /// /// 实时更新电机数据 /// /// private void UpdataRealTimeMotionData(Dictionary datasDic) { foreach(var dataItem in datasDic) { if (_axisNameIndexDic.ContainsKey(dataItem.Key)) { UpdateAxisData(_axisNameIndexDic[dataItem.Key], dataItem.Value); } } } /// /// 更新对应Axis数据 /// /// private void UpdateAxisData(int index, CommandMotionData data) { _galilControlData.GalilAxisDatas[index].Velocity = (int)data.ActualVelocity; _galilControlData.GalilAxisDatas[index].MotorPosition = (int)data.MotorPosition; _galilControlData.GalilAxisDatas[index].ReferencePosition = (int)data.TargetPosition; _galilControlData.GalilAxisDatas[index].Torque = (short)data.ActualTorque; } #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); } /// /// 设置目标位置 /// private void SetSpeed(char axis, int value) { _galilControlData.GalilAxisDatas[axis - 'A'].Velocity = value; } /// /// 设置目标绝对位置 /// private void SetTargetAbsolutePosition(char axis, int value) { _galilControlData.GalilAxisDatas[axis - 'A'].ReferencePosition = value; } /// /// 设置目标相对位置 /// private void SetTargetRelativePosition(char axis, int value) { _galilControlData.GalilAxisDatas[axis - 'A'].ReferencePosition += value; } #endregion } }