Browse Source

add galil controller

chenkui 2 months ago
parent
commit
731f2849fa

+ 3 - 0
CyberX8_Core/EventDefine.cs

@@ -151,6 +151,9 @@ namespace Aitex.Core.RT.Log{
 		INFO_FESTO = 6030,
 		WARN_FESTO = 6031,
 		ERR_FESTO = 6032,
+		INFO_GALIL = 6033,
+		WARN_GALIL = 6034,
+		ERR_GALIL = 6035,
 		ERROR_EFEM_COMMUNICATION = 10101001,
 		ERROR_EFEM_NOREADY = 10101002,
 		ERROR_EFEM_SORC_NOWAF = 10101003,

+ 12 - 0
CyberX8_RT/Config/Devices/GalilControllerCfg-Simulator.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<GalilControllerConfig>
+	<GalilDeviceConfig Module="PUF1" IpAddress="127.0.0.1" Port="58678" SendTimeout="2000" RecvTimeout="2000">
+		<GalilAxis Name="Flip" Index="0"/>
+		<GalilAxis Name="TILTA" Index="1"/>
+		<GalilAxis Name="CRSA" Index="2"/>
+		<GalilAxis Name="ROTATION" Index="3"/>
+		<GalilAxis Name="HORNB" Index="4"/>
+		<GalilAxis Name="TILTB" Index="5"/>
+		<GalilAxis Name="CRSB" Index="6"/>
+	</GalilDeviceConfig>
+</GalilControllerConfig>

+ 12 - 0
CyberX8_RT/Config/Devices/GalilControllerCfg.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<GalilControllerConfig>
+  <GalilDeviceConfig Module="PUF1" IpAddress="127.0.0.1" Port="58678" SendTimeout="2000" RecvTimeout="2000">
+	<GalilAxis Name="Flip" Index="0"/>
+	<GalilAxis Name="TILTA" Index="1"/>
+	<GalilAxis Name="CRSA" Index="2"/>
+	<GalilAxis Name="ROTATION" Index="3"/>
+	<GalilAxis Name="HORNB" Index="4"/>
+	<GalilAxis Name="TILTB" Index="5"/>
+	<GalilAxis Name="CRSB" Index="6"/>
+  </GalilDeviceConfig>
+</GalilControllerConfig>

+ 27 - 0
CyberX8_RT/Config/LogDefine.json

@@ -1352,6 +1352,33 @@
     "Note": "FESTO Error"
   },
   {
+    "Id": 6033,
+    "Level": "Info",
+    "LogEnum": "INFO_GALIL",
+    "GlobalDescription_zh": "{0}。",
+    "GlobalDescription_en": "{0}.",
+    "Module": "GALIL",
+    "Note": "GALIL Info"
+  },
+  {
+    "Id": 6034,
+    "Level": "Warning",
+    "LogEnum": "WARN_GALIL",
+    "GlobalDescription_zh": "{0}。",
+    "GlobalDescription_en": "{0}.",
+    "Module": "GALIL",
+    "Note": "GALIL Warning"
+  },
+  {
+    "Id": 6035,
+    "Level": "Error",
+    "LogEnum": "ERR_GALIL",
+    "GlobalDescription_zh": "{0}。",
+    "GlobalDescription_en": "{0}.",
+    "Module": "GALIL",
+    "Note": "GALIL Error"
+  },
+  {
     "Id": 10101001,
     "Level": "Error",
     "LogEnum": "ERROR_EFEM_COMMUNICATION",

+ 7 - 0
CyberX8_RT/CyberX8_RT.csproj

@@ -196,6 +196,7 @@
     <Compile Include="Devices\EFEM\SunWayMessageHandler.cs" />
     <Compile Include="Devices\Facilities\SystemFacilities.cs" />
     <Compile Include="Devices\FinsPlc.cs" />
+    <Compile Include="Devices\Galil\GalilAxis.cs" />
     <Compile Include="Devices\LinMot\LinmotDeviceTimer.cs" />
     <Compile Include="Devices\LinMot\LinMotAxis.cs" />
     <Compile Include="Devices\LinMot\LinMotStartContinueCurveRoutine.cs" />
@@ -498,6 +499,12 @@
     <Content Include="Config\Devices\FestoControllerCfg-Simulator.xml">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>
+    <Content Include="Config\Devices\GalilControllerCfg-Simulator.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Config\Devices\GalilControllerCfg.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
     <Content Include="Config\Devices\LinmotCfg-Simulator.xml">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>

+ 4 - 3
CyberX8_RT/Devices/DeviceManager.cs

@@ -32,6 +32,7 @@ using MECF.Framework.RT.Core.Equipments;
 using System.Threading;
 using MECF.Framework.Common.Device.PowerSupplier;
 using System.Reflection;
+using CyberX8_RT.Devices.Galil;
 
 namespace CyberX8_RT.Instances
 {
@@ -135,10 +136,10 @@ namespace CyberX8_RT.Instances
             BeckhoffAxis flipBeckhoffAxis = BeckhoffAxisManager.Instance.GetAxis($"{moduleName}.Flip");
             if (flipBeckhoffAxis != null)
             {
-                JetAxisBase pufFlipAxis = AxisManager.Instance.GetAxisInstance(flipBeckhoffAxis.MotorType, moduleName.ToString(), "Flip");
-                pufFlipAxis.InterLock = new PufFlipAxisInterLock(pufFlipAxis);
+                GalilAxis pufFlipAxis = new GalilAxis(moduleName.ToString(), "Flip");
+                //pufFlipAxis.InterLock = new PufFlipAxisInterLock(pufFlipAxis);
                 AddCustomModuleDevice(pufFlipAxis);
-                AxisManager.Instance.AddModuleAxis(moduleName.ToString(), pufFlipAxis);
+                //AxisManager.Instance.AddModuleAxis(moduleName.ToString(), pufFlipAxis);
             }
             BeckhoffAxis rotationBeckhoffAxis = BeckhoffAxisManager.Instance.GetAxis($"{moduleName}.Rotation");
             if (rotationBeckhoffAxis != null)

+ 130 - 0
CyberX8_RT/Devices/Galil/GalilAxis.cs

@@ -0,0 +1,130 @@
+using Aitex.Core.RT.Device;
+using MECF.Framework.Common.Beckhoff.IOAxis;
+using MECF.Framework.Common.CommonData.PUF;
+using MECF.Framework.Common.IOCore;
+using MECF.Framework.Common.TwinCat;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CyberX8_RT.Devices.Galil
+{
+    public class GalilAxis : BaseDevice, IDevice
+    {
+        #region 常量
+        private const string MOTOR_POSITION = "MotorPosition";
+        private const string POSITION_ERROR = "PositionError";
+        #endregion
+
+        #region 内部变量
+        /// <summary>
+        /// 变量是否初始化字典
+        /// </summary>
+        private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();
+        /// <summary>
+        /// 运动数据对象
+        /// </summary>
+        protected CommandMotionData _commandMotionData = new CommandMotionData();
+        #endregion
+
+        #region 属性
+        /// <summary>
+        /// 运动数据对象
+        /// </summary>
+        public CommandMotionData MotionData { get { return _commandMotionData; } }
+        #endregion
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="moduleName"></param>
+        /// <param name="name"></param>
+        public GalilAxis(string moduleName, string name) : base(moduleName, name, name, name)
+        {
+        }
+        #region public 公开方法
+        /// <summary>
+        /// 初始化
+        /// </summary>
+        /// <returns></returns>
+        public bool Initialize()
+        {
+            SubscribeValueAction();
+            return true;
+        }
+        /// <summary>
+        /// 订阅变量数值发生变化
+        /// </summary>
+        protected void SubscribeValueAction()
+        {
+            BeckhoffIoSubscribeUpdateVariable(MOTOR_POSITION);
+            BeckhoffIoSubscribeUpdateVariable(POSITION_ERROR);
+        }
+
+        /// <summary>
+        /// 订阅IO变量
+        /// </summary>
+        /// <param name="variable"></param>
+        private void BeckhoffIoSubscribeUpdateVariable(string variable)
+        {
+            _variableInitializeDic[variable] = false;
+            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}.{Name}", variable, UpdateVariableValue);
+        }
+        /// <summary>
+        /// 更新变量数值
+        /// </summary>
+        /// <param name="variable"></param>
+        /// <param name="value"></param>
+        protected void UpdateVariableValue(string variable, object value)
+        {
+            if (value == null)
+            {
+                return;
+            }
+            if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])
+            {
+                _variableInitializeDic[variable] = true;
+            }
+            UpdateMotionData(variable, value);
+        }
+        /// <summary>
+        /// 更新运动数据
+        /// </summary>
+        /// <param name="variable"></param>
+        /// <param name="value"></param>
+        private void UpdateMotionData(string variable, object value)
+        {
+            if (!MotionData.IsDataInitialized)
+            {
+                MotionData.IsDataInitialized = true;
+            }
+            PropertyInfo property = MotionData.GetType().GetProperty(variable);
+            if (property != null)
+            {
+                property.SetValue(MotionData, value);
+            }
+        }
+        #endregion
+
+
+        /// <summary>
+        /// 监控
+        /// </summary>
+        public void Monitor()
+        {
+
+        }
+        public void Reset()
+        {
+        }
+
+        /// 停止
+        /// </summary>
+        public void Terminate()
+        {
+        }
+    }
+}

+ 9 - 0
Framework/Common/Common.csproj

@@ -236,6 +236,15 @@
     <Compile Include="Device\Festo\FestoDO.cs" />
     <Compile Include="Device\Festo\FestoMessage.cs" />
     <Compile Include="Device\Festo\FestoModbusDevice.cs" />
+    <Compile Include="Device\Galil\GalilAxis.cs" />
+    <Compile Include="Device\Galil\GalilAxisData.cs" />
+    <Compile Include="Device\Galil\GalilCommand.cs" />
+    <Compile Include="Device\Galil\GalilControllerCfg.cs" />
+    <Compile Include="Device\Galil\GalilControllerCfgManager.cs" />
+    <Compile Include="Device\Galil\GalilControllerData.cs" />
+    <Compile Include="Device\Galil\GalilDeviceConfig.cs" />
+    <Compile Include="Device\Galil\GalilMessage.cs" />
+    <Compile Include="Device\Galil\GalilTcpDevice.cs" />
     <Compile Include="Device\LinMot\LinMotDelegate.cs" />
     <Compile Include="Device\PowerSupplier\PowerSupplierCommand.cs" />
     <Compile Include="Device\PowerSupplier\PowerSupplierDeviceConfigCfg.cs" />

+ 1 - 3
Framework/Common/Device/Festo/FestoControllerCfgManager.cs

@@ -42,9 +42,7 @@ namespace MECF.Framework.Common.Device.Festo
         /// <summary>
         /// do 索引对象字典(key-地址索引-bit,value--do名称)
         /// </summary>
-        private Dictionary<string, string> _doIndexDictionary = new Dictionary<string, string>();
-
-        
+        private Dictionary<string, string> _doIndexDictionary = new Dictionary<string, string>();        
         #endregion
         /// <summary>
         /// 初始化

+ 0 - 1
Framework/Common/Device/Festo/FestoModbusDevice.cs

@@ -65,7 +65,6 @@ namespace MECF.Framework.Common.Device.Festo
         {
             ReceiveTimeout = 1000;
             SendTimeout = 1000;
-            ReconnectInterval = 3000;
             ConnectTimeout = 1000;
             _name = name;
             _diStartAddress=diStartAddress;

+ 18 - 0
Framework/Common/Device/Galil/GalilAxis.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Schema;
+using System.Xml.Serialization;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilAxis
+    {
+        [XmlAttribute(AttributeName = "Name", Form = XmlSchemaForm.Unqualified, DataType = "string")]
+        public string Name { get; set; }
+        [XmlAttribute(AttributeName = "Index", Form = XmlSchemaForm.Unqualified, DataType = "int")]
+        public int Index { get; set; }
+    }
+}

+ 79 - 0
Framework/Common/Device/Galil/GalilAxisData.cs

@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilAxisData
+    {
+        public ushort Status { get; set; }
+
+        public byte Switches { get; set; }
+
+        public byte StopCode { get; set; }
+
+        public int ReferencePosition { get; set; }
+
+        public int MotorPosition { get; set;}
+
+        public int PositionError { get; set; }
+
+        public int AuxiliaryPosition { get; set; }
+
+        public int Velocity { get; set; }
+
+        public short Torque { get; set; }
+
+        public short Res { get; set; }
+
+        public bool IsSwitchOn { get; set; }
+
+        public bool ForwardLimit { get; set; }
+
+        public bool ReverseLimit { get; set; }
+        /// <summary>
+        /// 克隆
+        /// </summary>
+        /// <param name="data"></param>
+        public GalilAxisData Clone()
+        {
+            GalilAxisData data=new GalilAxisData();
+            data.Status= Status;
+            data.Switches= Switches;
+            data.StopCode= StopCode;
+            data.ReferencePosition= ReferencePosition;
+            data.MotorPosition= MotorPosition;
+            data.PositionError= PositionError;
+            data.AuxiliaryPosition= AuxiliaryPosition;
+            data.Velocity= Velocity;
+            data.Torque= Torque;
+            data.Res= Res;
+            data.IsSwitchOn= IsSwitchOn;
+            data.ForwardLimit= ForwardLimit;
+            data.ReverseLimit= ReverseLimit;
+            return data;
+        }
+        /// <summary>
+        /// 拷贝
+        /// </summary>
+        /// <param name="data"></param>
+        public void Copy(GalilAxisData data)
+        {
+            Status = data.Status;
+            Switches = data.Switches;
+            StopCode = data.StopCode;
+            ReferencePosition = data.ReferencePosition;
+            MotorPosition = data.MotorPosition;
+            PositionError = data.PositionError;
+            AuxiliaryPosition = data.AuxiliaryPosition;
+            Velocity = data.Velocity;
+            Torque = data.Torque;
+            Res = data.Res;
+            IsSwitchOn= IsSwitchOn;
+            ForwardLimit= ForwardLimit;
+            ReverseLimit= ReverseLimit;
+        }
+    }
+}

+ 29 - 0
Framework/Common/Device/Galil/GalilCommand.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilCommand
+    {
+        /// <summary>
+        /// 功能码
+        /// </summary>
+        public byte CommandCode { get; set; }
+
+        /// <summary>
+        /// 设置数据数组
+        /// </summary>
+        public byte[] Datas { get; set; }
+        /// <summary>
+        /// 设置数据
+        /// </summary>
+        public string SetData { get; set; }
+        /// <summary>
+        /// 接收的数据
+        /// </summary>
+        public GalilControllerData ControllerData { get; set; }
+    }
+}

+ 19 - 0
Framework/Common/Device/Galil/GalilControllerCfg.cs

@@ -0,0 +1,19 @@
+using MECF.Framework.Common.Device.Festo;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Schema;
+using System.Xml.Serialization;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    [XmlRoot("GalilControllerConfig")]
+    public class GalilControllerCfg
+    {
+
+        [XmlElement(Type = typeof(GalilDeviceConfig), ElementName = "GalilDeviceConfig", IsNullable = false, Form = XmlSchemaForm.Qualified)]
+        public List<GalilDeviceConfig> GalilDeviceConfigs { get; set; }
+    }
+}

+ 183 - 0
Framework/Common/Device/Galil/GalilControllerCfgManager.cs

@@ -0,0 +1,183 @@
+using Aitex.Common.Util;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.SCCore;
+using Aitex.Core.Util;
+using MECF.Framework.Common.Device.Festo;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.IOCore;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilControllerCfgManager : Singleton<GalilControllerCfgManager>
+    {
+        #region 常量 
+        private const string STOPCODE = "StopCode";
+        private const string REFERENCE_POSITION = "ReferencePosition";
+        private const string TORQUE = "Torque";
+        private const string VELOCITY = "Velocity";
+        private const string POSITION_ERROR = "PositionError";
+        private const string AUXILIARY_POSITION="AuxiliaryPosition";
+        #endregion
+
+        #region 内部变量
+        /// <summary>
+        /// 模块数据字典(key-模块名称,value-模块Galil数据)
+        /// </summary>
+        private Dictionary<string, GalilControllerData> _moduleGalilDataDictionary = new Dictionary<string, GalilControllerData>();
+        /// <summary>
+        /// 电机数据字典(key-电机名称,value-电机数据)
+        /// </summary>
+        private Dictionary<string, GalilAxisData> _moduleNameAxisDataDictionary = new Dictionary<string, GalilAxisData>();
+        /// <summary>
+        /// 电机索引字典(key-电机名称,value-索引)
+        /// </summary>
+        private Dictionary<string, int> _moduleNameIndexDictionary = new Dictionary<string, int>();
+        /// <summary>
+        /// 模块电机集合字典(key-模块名称,value-电机集合)
+        /// </summary>
+        private Dictionary<string,List<string>> _moduleNameLstDictionary= new Dictionary<string,List<string>>();
+        #endregion
+        /// <summary>
+        /// 初始化
+        /// </summary>
+        public void Initialize()
+        {
+            bool isSimulate = SC.GetValue<bool>("System.IsSimulatorMode");
+            string xmlPath = "";
+            try
+            {
+                if (isSimulate)
+                {
+                    xmlPath = PathManager.GetCfgDir() + "Devices\\GalilControllerCfg-Simulator.xml";
+                }
+                else
+                {
+                    xmlPath = PathManager.GetCfgDir() + "Devices\\GalilControllerCfg.xml";
+                }
+                GalilControllerCfg cfg = CustomXmlSerializer.Deserialize<GalilControllerCfg>(new FileInfo(xmlPath));
+                if (cfg != null)
+                {
+                    foreach (var config in cfg.GalilDeviceConfigs)
+                    {
+                        InitializeGalilDevice(config);
+                        GalilTcpDevice galilDevice = new GalilTcpDevice(config.Module, config.IpAddress, config.Port);
+                        galilDevice.ReceiveTimeout = config.RecvTimeout;
+                        galilDevice.SendTimeout = config.SendTimeout;
+                        galilDevice.Initialize();
+                    }
+                }
+            }
+            catch
+            {
+                LOG.WriteLog(eEvent.ERR_GALIL, "Galil", "Load galil xml failed");
+            }
+        }
+        /// <summary>
+        /// 初始化Galil 设备
+        /// </summary>
+        /// <param name="deviceConfig"></param>
+        private void InitializeGalilDevice(GalilDeviceConfig deviceConfig)
+        {
+            List<string> lst = new List<string>();
+            foreach(var item in deviceConfig.GalilAxises)
+            {
+                _moduleNameIndexDictionary[$"{deviceConfig.Module}.{item.Name}"] = item.Index;
+                if (!lst.Contains(item.Name))
+                {
+                    lst.Add(item.Name);
+                }
+            }
+            if (lst.Count > 0)
+            {
+                _moduleNameLstDictionary[deviceConfig.Module] = lst;
+            }
+        }
+        /// <summary>
+        /// 更新模块数据
+        /// </summary>
+        /// <param name="controllerData"></param>
+        public void UpdateModuleData(string module,GalilControllerData controllerData)
+        {
+            if (!_moduleGalilDataDictionary.ContainsKey(module))
+            {
+                _moduleGalilDataDictionary[module] = controllerData;
+            }
+            if (!_moduleNameLstDictionary.ContainsKey(module))
+            {
+                return;
+            }
+            List<string> lst = _moduleNameLstDictionary[module];
+            foreach (var item in lst)
+            {
+                string moduleName = $"{module}.{item}";
+                if (!_moduleNameIndexDictionary.ContainsKey(moduleName))
+                {
+                    continue;
+                }
+                int index = _moduleNameIndexDictionary[moduleName];
+                if(index>=controllerData.GalilAxisDatas.Count)
+                {
+                    continue;
+                }
+                GalilAxisData galilAxisData=controllerData.GalilAxisDatas[index];
+                CheckAxisDataChanged(moduleName, galilAxisData);
+            }
+        }
+        /// <summary>
+        /// 检验电机数据是否发生变化
+        /// </summary>
+        /// <param name="moduleName"></param>
+        /// <param name="axisData"></param>
+        private void CheckAxisDataChanged(string moduleName,GalilAxisData axisData)
+        {
+            if (_moduleNameAxisDataDictionary.ContainsKey(moduleName))
+            {
+                NotifyGalilAxisData(moduleName, _moduleNameAxisDataDictionary[moduleName],axisData);
+                _moduleNameAxisDataDictionary[moduleName].Copy(axisData);
+            }
+            else
+            {
+                NotifyGalilAxisAllData(moduleName, axisData);
+                _moduleNameAxisDataDictionary[moduleName] = axisData.Clone();
+            }
+        }
+        /// <summary>
+        /// 更新Galil电机数据
+        /// </summary>
+        /// <param name="axisData"></param>
+        private void NotifyGalilAxisAllData(string moduleName,GalilAxisData axisData)
+        {
+            PropertyInfo[] propertyInfos= axisData.GetType().GetProperties();
+            foreach(var info in propertyInfos)
+            {
+                object value = info.GetValue(axisData);
+                IOModuleManager.Instance.UpdateIoValue($"{moduleName}.{info.Name}", value);
+            }
+        }
+        /// <summary>
+        /// 通知Galil电机数据
+        /// </summary>
+        /// <param name="sourceData"></param>
+        /// <param name="targetData"></param>
+        private void NotifyGalilAxisData(string moduleName,GalilAxisData sourceData, GalilAxisData targetData)
+        {
+            PropertyInfo[] propertyInfos = sourceData.GetType().GetProperties();
+            foreach (var info in propertyInfos)
+            {
+                object sourceValue= info.GetValue(sourceData);
+                object targetValue = info.GetValue(targetData);
+                if (sourceValue.ToString() != targetValue.ToString())
+                {
+                    IOModuleManager.Instance.UpdateIoValue(moduleName, targetValue);
+                }
+            }
+        }
+    }
+}

+ 27 - 0
Framework/Common/Device/Galil/GalilControllerData.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilControllerData
+    {
+        public byte ErrorCode { get; set; }
+
+        public byte Status { get; set;}
+
+        public ushort Sample { get; set; }
+
+        public byte[] Inputs { get; set; }
+
+        public byte[] Outputs { get; set; }
+
+        public byte[] SBlocks { get; set; }
+
+        public byte[] TBlocks { get; set; }
+
+        public List<GalilAxisData> GalilAxisDatas { get; set; }
+    }
+}

+ 31 - 0
Framework/Common/Device/Galil/GalilDeviceConfig.cs

@@ -0,0 +1,31 @@
+using MECF.Framework.Common.Device.Festo;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Schema;
+using System.Xml.Serialization;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilDeviceConfig
+    {
+        [XmlAttribute(AttributeName = "Module", Form = XmlSchemaForm.Unqualified, DataType = "string")]
+        public string Module { get; set; }
+
+        [XmlAttribute(AttributeName = "IpAddress", Form = XmlSchemaForm.Unqualified, DataType = "string")]
+        public string IpAddress { get; set; }
+
+        [XmlAttribute(AttributeName = "Port", Form = XmlSchemaForm.Unqualified, DataType = "int")]
+        public int Port { get; set; }
+
+        [XmlAttribute(AttributeName = "SendTimeout", Form = XmlSchemaForm.Unqualified, DataType = "int")]
+        public int SendTimeout { get; set; }
+
+        [XmlAttribute(AttributeName = "RecvTimeout", Form = XmlSchemaForm.Unqualified, DataType = "int")]
+        public int RecvTimeout { get; set; }
+        [XmlElement(Type = typeof(GalilAxis), ElementName = "GalilAxis", IsNullable = false, Form = XmlSchemaForm.Qualified)]
+        public List<GalilAxis> GalilAxises { get; set; }
+    }
+}

+ 148 - 0
Framework/Common/Device/Galil/GalilMessage.cs

@@ -0,0 +1,148 @@
+using Aitex.Core.Utilities;
+using MECF.Framework.Common.Device.Festo;
+using MECF.Framework.Common.Device.PowerSupplier;
+using MECF.Framework.Common.Net;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilMessage : INetMessage<GalilCommand>
+    {
+        #region 属性
+        public int ProtocolHeadBytesLength { get; set; } = 1;
+
+        public int ErrorCode { get; set; }
+
+        public string ErrorMsg { get; set; }
+
+        public byte[] HeadBytes { get; set; }
+        public byte[] ContentBytes { get; set; }
+        public byte[] SendBytes { get; set; }
+        #endregion
+
+        #region 内部变量
+        IByteTransform byteTransform = new SmallEndianByteTransformBase();
+        #endregion
+
+        public bool CheckDataLegal()
+        {
+            return true;
+        }
+        public bool CheckHeadBytesLegal()
+        {
+            return true;
+        }
+
+
+        public bool ConfirmResponseResult()
+        {
+            return HeadBytes[0] == 0x3A;
+        }
+
+        public GalilCommand Decode()
+        {
+            GalilCommand command = new GalilCommand();
+            command.ControllerData = new GalilControllerData();
+            int offset = 0;
+            command.ControllerData.Sample = byteTransform.TransUInt16(ContentBytes, 0);
+            offset += 2;
+            int inputLength = 10;
+            command.ControllerData.Inputs = new byte[inputLength];
+            Array.Copy(ContentBytes,2,command.ControllerData.Inputs, 0, inputLength);
+            offset += inputLength;
+            int outputLength = 10;
+            command.ControllerData.Outputs = new byte[outputLength];
+            Array.Copy(ContentBytes,offset,command.ControllerData.Outputs,0, outputLength);
+            offset += outputLength;
+            command.ControllerData.ErrorCode = ContentBytes[offset];
+            offset += 1;
+            command.ControllerData.Status = ContentBytes[offset];
+            offset += 1;
+            int sBlockLength = 8;
+            command.ControllerData.SBlocks = new byte[sBlockLength];
+            Array.Copy(ContentBytes, offset, command.ControllerData.SBlocks, 0, sBlockLength);
+            offset += sBlockLength;
+            command.ControllerData.TBlocks = new byte[sBlockLength];
+            Array.Copy(ContentBytes,offset, command.ControllerData.TBlocks, 0, sBlockLength);
+            offset += sBlockLength;
+            int axisLength = 28;
+            command.ControllerData.GalilAxisDatas = new List<GalilAxisData>();
+            for(int i = offset; i < ContentBytes.Length; i += axisLength)
+            {
+                if(ContentBytes.Length-i < axisLength)
+                {
+                    break;
+                }
+                byte[] axisByt=new byte[axisLength];
+                Array.Copy(ContentBytes,i,axisByt,0,axisLength);
+                GalilAxisData galilAxisData = AnalyseAxisData(axisByt);
+                command.ControllerData.GalilAxisDatas.Add(galilAxisData);
+            }
+            return command;
+        }
+
+        private GalilAxisData AnalyseAxisData(byte[] data)
+        {
+            int offset = 0;
+            GalilAxisData axisData = new GalilAxisData();
+            axisData.IsSwitchOn = (data[0] & 0x01)==0x00;
+            axisData.Status=byteTransform.TransUInt16(data,offset);
+            offset += 2;
+            axisData.Switches = data[offset];
+            axisData.ForwardLimit = ((axisData.Switches >> 3) & 0x01) == 0x01;
+            axisData.ReverseLimit = ((axisData.Switches >> 2) & 0x01) == 0x01;
+            offset += 1;
+            axisData.StopCode = data[offset];
+            offset += 1;
+            axisData.ReferencePosition=byteTransform.TransInt32(data,offset);
+            offset += 4;
+            axisData.MotorPosition = byteTransform.TransInt32(data, offset);
+            offset += 4;
+            axisData.PositionError=byteTransform.TransInt32(data,offset);
+            offset += 4;
+            axisData.AuxiliaryPosition=byteTransform.TransInt32(data,offset);
+            offset += 4;
+            axisData.Velocity=byteTransform.TransInt32(data,offset);
+            offset += 4;
+            axisData.Torque = byteTransform.TransInt16(data, offset);
+            offset += 2;
+            axisData.Res=byteTransform.TransInt16(data,offset);
+            return axisData;
+        }
+
+        public int GetContentLengthByHeadBytes()
+        {
+            if (HeadBytes.Length > 1)
+            {
+                return byteTransform.TransInt16(HeadBytes, 2)-ProtocolHeadBytesLength+1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
+        public int GetHeadBytesIdentity()
+        {
+            return byteTransform.TransInt16(HeadBytes, 0);
+        }
+
+        public byte[] Code(GalilCommand data)
+        {
+            if (data.CommandCode == 3)
+            {
+                ProtocolHeadBytesLength = 4;
+            }
+            return ASCIIEncoding.ASCII.GetBytes(data.SetData);     
+        }
+
+        public void SetProtocolHeadBytesLength()
+        {
+
+        }
+    }
+}

+ 207 - 0
Framework/Common/Device/Galil/GalilTcpDevice.cs

@@ -0,0 +1,207 @@
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using MECF.Framework.Common.Device.Festo;
+using MECF.Framework.Common.Net;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MECF.Framework.Common.Device.Galil
+{
+    public class GalilTcpDevice : JetMessageTcpClient<GalilMessage, GalilCommand>
+    {
+        #region 内部变量
+        /// <summary>
+        /// 名称
+        /// </summary>
+        private string _module;
+        /// <summary>
+        /// 上一次错误信息
+        /// </summary>
+        private string _lastErrorMsg = "";
+        /// <summary>
+        /// IP地址
+        /// </summary>
+        private string _ip = "";
+        /// <summary>
+        /// 端口号
+        /// </summary>
+        private int _port = 502;
+        /// <summary>
+        /// 定时器
+        /// </summary>
+        private PeriodicJob _periodicJob;
+        /// <summary>
+        /// 共享锁
+        /// </summary>
+        private object _locker = new object();
+        /// <summary>
+        /// 共享锁时长
+        /// </summary>
+        private int _lockerTime = 2000;
+        #endregion
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="ip"></param>
+        /// <param name="port"></param>
+        public GalilTcpDevice(string module, string ip, int port) : base(ip, port)
+        {
+            ReceiveTimeout = 1000;
+            SendTimeout = 1000;
+            ConnectTimeout = 1000;
+            _module = module;
+            _ip = ip;
+            _port = port;
+            _periodicJob = new PeriodicJob(200, OnTimer, $"Galil {_module} timer", false, true);
+        }
+        /// <summary>
+        /// 定时器执行
+        /// </summary>
+        /// <returns></returns>
+        private bool OnTimer()
+        {
+            if (Monitor.TryEnter(_locker, _lockerTime))
+            {
+                ApplyAllDatas();
+                Monitor.Exit(_locker);
+            }
+            return true;
+        }
+        /// <summary>
+        /// 更新地址数量
+        /// </summary>
+        /// <param name="addressCount"></param>
+        public void Initialize()
+        {
+            NetResult result = Connect();
+            if (result.IsSuccess)
+            {
+                ApplyAllDatas();
+                LOG.WriteLog(eEvent.INFO_FESTO, _module, $"connect {_ip}:{_port} success");
+            }
+            else
+            {
+                LOG.WriteLog(eEvent.INFO_FESTO, _module, $"connect {_ip}:{_port} failed");
+            }
+
+            _periodicJob.Start();
+        }
+        /// <summary>
+        /// 设置Festo数值
+        /// </summary>
+        /// <param name="address"></param>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public bool SetGalilCommand(ushort address, string command)
+        {
+            GalilCommand galiCommand = new GalilCommand();
+            galiCommand.CommandCode = 0x06;
+            galiCommand.SetData = command;
+            if (Monitor.TryEnter(_locker, _lockerTime))
+            {
+                bool result = SetOperation(galiCommand);
+                Monitor.Exit(_locker);
+                return result;
+            }
+            else
+            {
+                WriteErrMsg($"Write apply locker over {_lockerTime}");
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 设置操作
+        /// </summary>
+        /// <param name="command"></param>
+        /// <returns></returns>
+        private bool SetOperation(GalilCommand command)
+        {
+            if (Connected)
+            {
+                return WriteCommand(command);
+            }
+            else
+            {
+                NetResult netResult = Connect();
+                if (netResult.IsSuccess)
+                {
+                    return WriteCommand(command);
+                }
+                else
+                {
+                    WriteErrMsg("connect failed");
+                    return false;
+                }
+            }
+        }
+        /// <summary>
+        /// 写指令 
+        /// </summary>
+        /// <param name="command"></param>
+        /// <returns></returns>
+        private bool WriteCommand(GalilCommand command)
+        {
+            NetResult netResult = SetData(command);
+            if (!netResult.IsSuccess)
+            {
+                WriteErrMsg($"write value {command.SetData} failed,{netResult.Message}");
+                return false;
+            }
+            return true;
+        }
+        /// <summary>
+        /// 申请所有数据
+        /// </summary>
+        public void ApplyAllDatas()
+        {
+            GalilCommand command = new GalilCommand();
+            command.CommandCode = 0x03;
+            command.SetData = "QR;";
+            ApplyDataOperation(command);
+        }
+        /// <summary>
+        /// 申请数据操作
+        /// </summary>
+        /// <param name="command"></param>
+        private void ApplyDataOperation(GalilCommand command)
+        {
+            if (!Connected)
+            {
+                NetResult connectResult = Connect();
+                if (!connectResult.IsSuccess)
+                {
+                    WriteErrMsg("connect failed");
+                    return;
+                }
+            }
+            NetResult<GalilCommand> netResult = ApplyData(command);
+            if (!netResult.IsSuccess)
+            {
+                WriteErrMsg($"apply data failed,{netResult.Message}");
+                return;
+            }
+            else
+            {
+                GalilControllerCfgManager.Instance.UpdateModuleData(_module, netResult.Data.ControllerData);
+            }
+        }
+        /// <summary>
+        /// 写错误日志
+        /// </summary>
+        /// <param name="msg"></param>
+        private void WriteErrMsg(string msg)
+        {
+            if (msg != _lastErrorMsg)
+            {
+                _lastErrorMsg = msg;
+
+                LOG.WriteLog(eEvent.ERR_GALIL, _module, msg);
+            }
+        }
+    }
+}

+ 2 - 0
Framework/Common/IOCore/IOModuleManager.cs

@@ -3,6 +3,7 @@ using Aitex.Core.RT.SCCore;
 using Aitex.Core.Util;
 using MECF.Framework.Common.Beckhoff.ModuleIO;
 using MECF.Framework.Common.Device.Festo;
+using MECF.Framework.Common.Device.Galil;
 using MECF.Framework.Common.TwinCat;
 using System;
 using System.Collections.Generic;
@@ -34,6 +35,7 @@ namespace MECF.Framework.Common.IOCore
         public void Initialize()
         {
             FestoControllerCfgManager.Instance.Initialize(_festoName);
+            GalilControllerCfgManager.Instance.Initialize();
         }
         /// <summary>
         /// 写IO数值

+ 13 - 9
Framework/Common/Net/JetMessageTcpClient.cs

@@ -104,16 +104,20 @@ namespace MECF.Framework.Common.Net
             {
                 return NetResult.CreateFailedResult(NetErrorCode.InvalidHeader);
             }
-            NetResult<byte[]> contentResult = Receive(_netMessage.GetContentLengthByHeadBytes());
-            if (!contentResult.IsSuccess)
+            int contentLength = _netMessage.GetContentLengthByHeadBytes();
+            if (contentLength !=0)
             {
-                return NetResult.CreateFailedResult(contentResult.ErrorCode, contentResult.Message);
-            }
-            _netMessage.ContentBytes = contentResult.Data;
-            bool dataValid = _netMessage.CheckDataLegal();
-            if(!dataValid)
-            {
-                return NetResult.CreateFailedResult(_netMessage.ErrorCode,_netMessage.ErrorMsg);
+                NetResult<byte[]> contentResult = Receive(contentLength);
+                if (!contentResult.IsSuccess)
+                {
+                    return NetResult.CreateFailedResult(contentResult.ErrorCode, contentResult.Message);
+                }
+                _netMessage.ContentBytes = contentResult.Data;
+                bool dataValid = _netMessage.CheckDataLegal();
+                if (!dataValid)
+                {
+                    return NetResult.CreateFailedResult(_netMessage.ErrorCode, _netMessage.ErrorMsg);
+                }
             }
             return NetResult.CreateSuccessResult();
         }

+ 9 - 1
Framework/Common/Net/JetTcpClient.cs

@@ -252,7 +252,15 @@ namespace MECF.Framework.Common.Net
                 }
                 try
                 {
-                    byte[] buffer = new byte[length];
+                    byte[] buffer = null;
+                    if (length == -1)
+                    {
+                        buffer = new byte[_socket.Available];
+                    }
+                    else
+                    {
+                        buffer = new byte[length];
+                    }
                     _socket.Receive(buffer, length, SocketFlags.None);
                     Monitor.Exit(_receiveLocker);
                     return NetResult.CreateSuccessResult<byte[]>(buffer);