using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reactive.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using SystemX.Net.Platform.Common.Event; using SystemX.Net.Platform.Common.Util; using static SystemX.PLC.Interface.PLCCommDefinition; namespace SystemX.PLC.Interface.MxComponent { public class PLCDeviceMXC { public FunctionEventHandler EventAlwaysUpdate { get; set; } public FunctionEventHandler EventChangeUpdate { get; set; } public int STATION_ID { set; get; } //PLC STATION private int ScanningIntervalOperation = 100; private int ScanningIntervalDataTime = 500; private bool MonitorExe = true; private Stopwatch stReadTimeCheck; private PLCMxComponent _conn; //MxComponent PLC Instance Dictionary DicOperationAddresses = new Dictionary(); Dictionary DicDataAddresses = new Dictionary(); Stopwatch xSwDiag = new Stopwatch(); private static object objLock = new object(); public PLCDeviceMXC() { stReadTimeCheck = new Stopwatch(); stReadTimeCheck.Start(); } public bool DevClose() { if (_conn != null) { StopMonitor(); return _conn.Close(); } return true; } public bool DevOpen() { try { _conn = new PLCMxComponent(); _conn.Initialize(); return _conn.Open(STATION_ID.ToString()); } catch (Exception ex) { LogMessage.MessageOutput.ConsoleWrite($"Error during PLC Open : {ex.Message}", ConsoleColor.Red, LogMessage.LogMessageLevel.FATAL); return false; } } public bool AddOperationDevices(PLCAddressTemplate deviceReg) { DicOperationAddresses.Add(deviceReg.PLCAddress, deviceReg); return true; } public bool AddDataDevices(PLCAddressTemplate deviceReg) { DicDataAddresses.Add(deviceReg.PLCAddress, deviceReg); return true; } public void SingleScanStartAsync() { lock (objLock) { ScanDataArea(); ScanOperationArea(true); } } public void NowDataAreaScan() { lock (objLock) { ScanDataArea(); } } public void StartMonitor() { MonitorExe = true; Task monitor = new Task(() => ExecuteMonitor().Result); monitor.Start(); } public void StopMonitor() { MonitorExe = false; } private async Task ExecuteMonitor() { //int nCountTime = 0; stReadTimeCheck.Restart(); while (MonitorExe) { lock (objLock) { ScanOperationArea(); /* if (stReadTimeCheck.ElapsedMilliseconds >= ScanningIntervalDataTime) { ScanDataArea(); stReadTimeCheck.Restart(); } */ // /* if (nCountTime % ScanningIntervalDataTime == 0) { nCountTime = 1; ScanDataArea(); } nCountTime++; */ } await Task.Delay(ScanningIntervalOperation); } return 0; } void ScanDataArea() { foreach (PLCAddressTemplate addrTemplate in DicDataAddresses.Values) UpdateDevice(addrTemplate, true); } void ScanOperationArea(bool bSingleScan = false) { foreach (PLCAddressTemplate addrTemplate in DicOperationAddresses.Values) { string strFormerValue = addrTemplate.Value; UpdateDevice(addrTemplate, true); EventAlwaysUpdate.DoReceive(this, addrTemplate); if (addrTemplate.Value != strFormerValue) EventChangeUpdate.DoReceive(this, addrTemplate); if (bSingleScan) EventChangeUpdate.DoReceive(this, addrTemplate); } } public string GetModuleName() { return Assembly.GetExecutingAssembly().ManifestModule.Name.Replace(".dll", string.Empty); } Int16[] ReadPLCData(PLCAddressTemplate template) { if (_conn == null) return null; int nSize = Convert.ToInt32(template.Length); Int16[] readData = new Int16[nSize]; _conn.BlockReadData(template.PLCAddress, nSize, ref readData); return readData; } bool WritePLCData(PLCAddressTemplate template, Int16[] arnWriteData) { if (_conn == null) return false; int nSize = Convert.ToInt32(template.Length); bool ret = _conn.BlockWriteData(template.PLCAddress, nSize, arnWriteData); if (ret == false) { _conn.BlockWriteData(template.PLCAddress, nSize, arnWriteData); Thread.Sleep(30); } Thread.Sleep(30); //bool ret = PLC_COMM.WriteData(addr, nSize, arnWriteData); return ret; } List GetReadValues(PLCAddressTemplate tmplt) { int nLength = Convert.ToInt32(tmplt.Length); List vnValues = (from value in ReadPLCData(tmplt) let value32 = Convert.ToInt32(value) select value32).ToList(); return vnValues; } List GetWriteValues(PLCAddressTemplate tmplt, string strValue) { List vnValues = new List(); int nLength = Convert.ToInt32(tmplt.Length); eDataType eType = (eDataType)Enum.Parse(typeof(eDataType), tmplt.DataType); if (eType == eDataType.ASCII) vnValues = (from value in CommonUtil.HexStringToBytes(strValue) select Convert.ToInt16(value)).ToList(); else if (eType == eDataType.DECIMAL) { int nInputValue = string.IsNullOrWhiteSpace(strValue) ? 0 : Convert.ToInt16(strValue); vnValues.Add(Convert.ToInt16(nInputValue)); } return vnValues; } void UpdateValue(PLCAddressTemplate tmplt, bool bRefineWrongChar, bool bAsciiReverseBit = false) { List vValues = GetReadValues(tmplt); eDataType eType = (eDataType)Enum.Parse(typeof(eDataType), tmplt.DataType); string strData = string.Empty; if (eType == eDataType.ASCII) strData = CommonUtil.GetStringFromASCII(vValues.ToArray(), bAsciiReverseBit); else if (eType == eDataType.BIT) strData = vValues[0].ToString(); else if (eType == eDataType.DECIMAL) strData = vValues[0].ToString(); string strResult = bRefineWrongChar ? RefineInvalidChars(strData) : strData; tmplt.SetStringValue(strResult); } string RefineInvalidChars(string strSource) { string strReturn = strSource.Trim(InvalidChars); strReturn = new string((from cCode in strSource.ToCharArray() where (48 <= Convert.ToInt32(cCode) && Convert.ToInt32(cCode) <= 95) select cCode).ToArray()); return strReturn; } public string GetDeviceValue(PLCAddressTemplate tmplt) { List Oper = DicOperationAddresses.Values.Where(x => x.DataName == tmplt.DataName).ToList(); List Data = DicDataAddresses.Values.Where(x => x.DataName == tmplt.DataName).ToList(); if (Oper.Count > 0) return Oper.First().Value; else if (Data.Count > 0) return Data.First().Value; else return string.Empty; } public PLCAddressTemplate UpdateDevice(PLCAddressTemplate tmplt, bool bRefineWrongChar, bool bAsciiReverse = false) { if (tmplt == null) { LogMessage.MessageOutput.ConsoleWrite($"Cannot Find a Corresponding Data."); return null; } UpdateValue(tmplt, bRefineWrongChar, bAsciiReverse); return tmplt; } public bool WriteDevice(PLCAddressTemplate tmplt, string strValue) { List vValues = GetWriteValues(tmplt, strValue); return WritePLCData(tmplt, vValues.ToArray()); } } }