using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Windows.Forms.VisualStyles; using Aitex.Core.RT.Log; using Aitex.Core.RT.PLC; using Aitex.Core.Util; namespace Aitex.Core.RT.IOCore { public class IOGroupManager { public const int DioBlockLength = 200; public const int AioBlockLength = 200; private Dictionary<string, IO_DEFINE> _ioDefine = new Dictionary<string, IO_DEFINE>(); private object _iomapLocker = new object(); private Dictionary<string, object> _ioMap = new Dictionary<string, object>(); private Dictionary<string, bool[]> _di = new Dictionary<string, bool[]>(); private Dictionary<string, bool[]> _do = new Dictionary<string, bool[]>(); private Dictionary<string, float[]> _ai = new Dictionary<string, float[]>(); private Dictionary<string, float[]> _ao = new Dictionary<string, float[]>(); private InterlockManager _interlock = new InterlockManager(); private PeriodicJob _monitorThread; private Dictionary<string, int[]> _dicPlcIoBaseAddress = new Dictionary<string, int[]>(); public void Initialize(Dictionary<string, string> ioDefineXmlFile, string interlockConfigFile, Dictionary<string, int[]> plcIoBaseAddress, List<string> logicDi) { _dicPlcIoBaseAddress = plcIoBaseAddress; try { foreach (var item in ioDefineXmlFile) { if (!File.Exists(item.Value)) throw new Exception(string.Format("IO item define file not exist, {0}", item.Value)); _ioDefine[item.Key] = CustomXmlSerializer.Deserialize<IO_DEFINE>(new FileInfo(item.Value)); _di[item.Key] = new bool[DioBlockLength]; _do[item.Key] = new bool[DioBlockLength]; _ai[item.Key] = new float[AioBlockLength]; _ao[item.Key] = new float[AioBlockLength]; IOMapping(item.Key, plcIoBaseAddress[item.Key]); } } catch (Exception ex) { LOG.Write(ex); throw new Exception(string.Format("IO define file found error, \r\n {0}", ex.Message)); } _di["logic"] = new bool[DioBlockLength]; int index = 0; foreach (var diName in logicDi) { DIAccessor diAccessor = new DIAccessor(diName, index, _di["logic"], _di["logic"]); _ioMap[diName] = diAccessor; diAccessor.IoTableIndex = index; index++; } string reason = string.Empty; if (!_interlock.Initialize(interlockConfigFile, _ioMap, out reason)) { throw new Exception(string.Format("interlock define file found error: \r\n {0}", reason)); } _monitorThread = new PeriodicJob(200, OnTimer, "IO Monitor Thread", true); } private bool OnTimer() { try { _interlock.Monitor(); } catch (Exception ex) { LOG.Write(ex); } return true; } public void Update<T, V>(string group, IDataBuffer<T, V> buf) where T : struct where V : struct { buf.UpdateDI(_di[group]); buf.UpdateDO(_do[group]); buf.UpdateAI(_ai[group]); buf.UpdateAO(_ao[group]); } public T GetIO<T>(string name) where T : class { T obj = null; lock (_iomapLocker) { if (_ioMap.ContainsKey(name)) obj = _ioMap[name] as T; } if (obj == null) { if (!String.IsNullOrWhiteSpace(name)) LOG.Error(string.Format("IO not match, can not find {0}", name)); } return obj; } private void IOMapping(string group, int[] plcIoBaseAddress) { lock (_iomapLocker) { //DI foreach (DI_ITEM item in _ioDefine[group].Dig_In) { if (string.IsNullOrEmpty(item.Name)) continue; int index = GetIndex(item.Addr, plcIoBaseAddress[0]); if (index > 200) { LOG.Write(String.Format("DI {0} mapping index larger than buffer, addr is {1}", item.Index, item.Addr)); } if (index >= 0) { DIAccessor diAccessor = new DIAccessor(item.Name, index, _di[group], _di[group]); _ioMap[item.Name] = diAccessor; diAccessor.IoTableIndex = item.Index; //DATA.Subscribe(String.Format("IO.DI.{0}", item.Name), () => { return diAccessor.Value; }); } else { LOG.Write(String.Format("DI{0} mapping error, addr is {1}", item.Index, item.Addr)); } } //DO foreach (DO_ITEM item in _ioDefine[group].Dig_Out) { if (string.IsNullOrEmpty(item.Name)) continue; int index = GetIndex(item.Addr, plcIoBaseAddress[1]); if (index > 200) { LOG.Write(String.Format("DO {0} mapping index larger than buffer, addr is {1}", item.Index, item.Addr)); } if (index >= 0) { DOAccessor doAccessor = new DOAccessor(item.Name, index, _do[group]); _ioMap[item.Name] = doAccessor; doAccessor.IoTableIndex = item.Index; //DATA.Subscribe(String.Format("IO.DO.{0}", item.Name), () => { return doAccessor.Value; }); } else { LOG.Write(String.Format("DO{0} mapping error, addr is {1}", item.Index, item.Addr)); } } //AI foreach (AI_ITEM item in _ioDefine[group].Ana_In) { if (string.IsNullOrEmpty(item.Name)) continue; int index = GetIndex(item.Addr, plcIoBaseAddress[2]); if (index > 200) { LOG.Write(String.Format("AI {0} mapping index larger than buffer, addr is {1}", item.Index, item.Addr)); } if (index >= 0) { AIAccessor aiAccessor = new AIAccessor(item.Name, index, _ai[group]); _ioMap[item.Name] = aiAccessor; aiAccessor.IoTableIndex = item.Index; //DATA.Subscribe(String.Format("IO.AI.{0}", item.Name), () => { return aiAccessor.Value; }); } else { LOG.Write(String.Format("AI{0} mapping error, addr is {1}", item.Index, item.Addr)); } } //AO foreach (AO_ITEM item in _ioDefine[group].Ana_Out) { if (string.IsNullOrEmpty(item.Name)) continue; int index = GetIndex(item.Addr, plcIoBaseAddress[3]); if (index > 200) { LOG.Write(String.Format("AO {0} mapping index larger than buffer, addr is {1}", item.Index, item.Addr)); } if (index >= 0) { AOAccessor aoAccessor = new AOAccessor(item.Name, index, _ao[group]); _ioMap[item.Name] = aoAccessor; aoAccessor.IoTableIndex = item.Index; //DATA.Subscribe(String.Format("IO.AO.{0}", item.Name), () => { return aoAccessor.Value; }); } else { LOG.Write(String.Format("AO{0} mapping error, addr is {1}", item.Index, item.Addr)); } } } } private int GetIndex(string addr, int first) { if (String.IsNullOrEmpty(addr)) { LOG.Write("GetIndex addr is empty"); return -1; } string[] parts = addr.Trim().ToUpper().Split('.'); int len = parts.Length; if (len == 1) { string ch = parts[0].TrimStart('D'); int index = Convert.ToUInt16(ch); return (index - first) / 2; } if (len == 2) { char[] trim = { 'W', 'C', 'I', 'O', ' ' }; string ch = parts[0].TrimStart(trim); int index = Convert.ToUInt16(ch); int bit = Convert.ToUInt16(parts[1]); return (index - first) * 16 + bit; } LOG.Info("IOManager GetIndex error"); return -1; } public bool CanSetDo(string doName, bool onOff, out string reason) { return _interlock.CanSetDo(doName, onOff, out reason); } public List<Tuple<int, int, string>> GetIONameList(string group, IOType ioType) { List<Tuple<int, int, string>> result = new List<Tuple<int, int, string>>(); if (!_dicPlcIoBaseAddress.ContainsKey(group)) return result; int[] plcIoBaseAddress = _dicPlcIoBaseAddress[group]; switch (ioType) { case IOType.AI: foreach (AI_ITEM item in _ioDefine[group].Ana_In) { if (string.IsNullOrEmpty(item.Name)) continue; result.Add(Tuple.Create(item.Index, GetIndex(item.Addr, plcIoBaseAddress[2]), item.Name)); } break; case IOType.AO: foreach (AO_ITEM item in _ioDefine[group].Ana_Out) { if (string.IsNullOrEmpty(item.Name)) continue; result.Add(Tuple.Create(item.Index, GetIndex(item.Addr, plcIoBaseAddress[3]), item.Name)); } break; case IOType.DI: foreach (DI_ITEM item in _ioDefine[group].Dig_In) { if (string.IsNullOrEmpty(item.Name)) continue; result.Add(Tuple.Create(item.Index, GetIndex(item.Addr, plcIoBaseAddress[0]), item.Name)); } break; case IOType.DO: foreach (DO_ITEM item in _ioDefine[group].Dig_Out) { if (string.IsNullOrEmpty(item.Name)) continue; result.Add(Tuple.Create(item.Index, GetIndex(item.Addr, plcIoBaseAddress[1]), item.Name)); } break; } return result; } public void Terminate() { try { _monitorThread.Stop(); } catch (Exception ex) { LOG.Write(ex); } } } }