// Ignore Spelling: timestamp Cmp using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IACommService4CSharp { public class AXClient_t : IDisposable { private IClient4CSharp m_client; private bool m_bSymbolNameEncode; private bool m_disposed; private IReadCompleteCallback_t m_readCompleteCallback; private IWriteCompleteCallback_t m_writeCompleteCallback; private IDataChangeCallback_t m_dataChangeCallback; private readonly object m_locker = new object(); private Dictionary m_symbolListCache = new Dictionary(); public static uint BrowseAsync(string gatewayIP, string gatewayPort, IBrowseDeviceCallback_t browseCallback) { if (null == browseCallback || (null == gatewayIP && null != gatewayPort) || (null != gatewayIP && null == gatewayPort)) return ErrorCode.InvalidArgument; DataValue_t gatewayInfos = null; if (gatewayIP != null && gatewayPort != null) { gatewayInfos = new DataValue_t(DType.Complex); var gatewayInfo = new DataValue_t(DType.String); gatewayInfo.SetValue(gatewayIP); gatewayInfos.SetValue("GatewayIPAddress", gatewayInfo); gatewayInfo.SetValue(gatewayPort); gatewayInfos.SetValue("GatewayPort", gatewayInfo); gatewayInfo.Dispose(); } var clientMgr = CommClientManager as ICommClientManager24CSharp; if (null == clientMgr) return ErrorCode.NotSupported; var status = clientMgr.BrowseAsync("AXDriver", gatewayInfos == null ? null : gatewayInfos.Internal, browseCallback); if (gatewayInfos != null) gatewayInfos.Dispose(); return status; } /* Parameter bool 'bSymbolNameEncode' : 'false' is mean that the instance of AXClient_t adapt to the symbol name encoding of DIADesigner-AX 1.5 or later, or other AX designer which install CODOSYS communication 4.3 or later add-on. 'true' is mean that the instance of AXClient_t adapt to the symbol name encoding of DIADesigner-AX 1.4 or below, and which did not install CODOSYS communication 4.3 or later add-on. */ public AXClient_t(bool bSymbolNameEncode = false) { m_client = CommClientManager.CreateClient("AXDriver"); if (null == m_client) throw new IACommServiceException(ErrorCode.InternalError); m_bSymbolNameEncode = bSymbolNameEncode; m_disposed = false; } ~AXClient_t() { Dispose(false); } public uint Connect(string axIPAddr, string port = "11740", string userName = null, string password = null) { if (null == m_client) return ErrorCode.InvalidState; if (null == axIPAddr || null == port) return ErrorCode.InvalidArgument; GeneralConfig_t config = new GeneralConfig_t(); config.SetParameter("IPAddress", axIPAddr); config.SetParameter("Port", port); if (userName != null) config.SetParameter("User", userName); if (password != null) config.SetParameter("Password", password); config.SetParameter("SymbolNameEncode", m_bSymbolNameEncode ? "Yes" : "No"); return m_client.Connect(config.Internal); } public uint ConnectViaGateway(string gatewayIPAddr, string gatewayPort, string axIPAddr, string port = "11740", string userName = null, string password = null) { if (null == m_client) return ErrorCode.InvalidState; if (null == gatewayIPAddr || null == gatewayPort || null == axIPAddr || null == port) return ErrorCode.InvalidArgument; GeneralConfig_t config = new GeneralConfig_t(); //Add gateway connector configuration config.SetParameter("GatewayEnable", "Enabled"); config.SetParameter("GatewayName", "Gateway1"); config.SetParameter("GatewayIpAddress", gatewayIPAddr); config.SetParameter("GatewayPort", gatewayPort); //Add AX Device connect configuration config.SetParameter("IPAddress", axIPAddr); config.SetParameter("Port", port); if (userName != null) config.SetParameter("User", userName); if (password != null) config.SetParameter("Password", password); return m_client.Connect(config.Internal); } public uint ConnectByAddress(string axAddress /*logical address*/, string userName = null, string password = null) { if (null == m_client) return ErrorCode.InvalidState; if (null == axAddress) return ErrorCode.InvalidArgument; GeneralConfig_t config = new GeneralConfig_t(); config.SetParameter("Address", axAddress); config.SetParameter("ConnectType", "Logical_Address"); if (userName != null) config.SetParameter("User", userName); if (password != null) config.SetParameter("Password", password); return m_client.Connect(config.Internal); } public uint ConnectViaGatewayByAddress(string gatewayIPAddr, string gatewayPort, string axAddress /*logical address*/, string userName = null, string password = null) { if (null == m_client) return ErrorCode.InvalidState; if (null == gatewayIPAddr || null == gatewayPort || null == axAddress) return ErrorCode.InvalidArgument; GeneralConfig_t config = new GeneralConfig_t(); //Add gateway connector configuration config.SetParameter("GatewayEnable", "Enabled"); config.SetParameter("GatewayName", "Gateway1"); config.SetParameter("GatewayIpAddress", gatewayIPAddr); config.SetParameter("GatewayPort", gatewayPort); //Add AX Device connect configuration config.SetParameter("Address", axAddress); config.SetParameter("ConnectType", "Logical_Address"); if (userName != null) config.SetParameter("User", userName); if (password != null) config.SetParameter("Password", password); return m_client.Connect(config.Internal); } public uint Disconnect() { return m_client.Disconnect(); } public uint Read(string symbolName, ref DataItem_t dataItem) { if (null == symbolName) return ErrorCode.InvalidArgument; if (dataItem is null) dataItem = new DataItem_t(); var addressList = new string[1] { symbolName }; var dataItemList = new DataItem_t[1] { dataItem }; return Read(addressList, ref dataItemList); } public uint Read(string[] symbolNameList, ref DataItem_t[] dataItemList) { if (null == symbolNameList) return ErrorCode.InvalidArgument; if (0 == symbolNameList.Length) return ErrorCode.NothingToDo; if (dataItemList is null) { dataItemList = new DataItem_t[symbolNameList.Length]; } else if(dataItemList.Length < symbolNameList.Length) { var tempList = dataItemList.ToList(); while(tempList.Count < symbolNameList.Length) { tempList.Add(new DataItem_t()); } dataItemList = tempList.ToArray(); } else if(dataItemList.Length > symbolNameList.Length) { var tempList = dataItemList.ToList(); tempList.RemoveRange(symbolNameList.Length, dataItemList.Length - symbolNameList.Length); dataItemList = tempList.ToArray(); } var dataItemInternals = new IDataItem4CSharp[dataItemList.Length]; for (int index = 0; index < dataItemList.Length; index++) { if (dataItemList[index] is null) dataItemList[index] = new DataItem_t(); dataItemInternals[index] = dataItemList[index].Internal; } return m_client.Read(symbolNameList, dataItemInternals); } public void SetReadAsyncCallback(IReadCompleteCallback_t callback) { m_readCompleteCallback = callback; } public uint ReadAsync(string[] symbolNameList) { if (null == symbolNameList) return ErrorCode.InvalidArgument; if (0 == symbolNameList.Length) return ErrorCode.NothingToDo; uint transactionId = 0; if (m_readCompleteCallback != null) m_readCompleteCallback.Lock(); uint status = m_client.ReadAsync(symbolNameList, m_readCompleteCallback, ref transactionId); if (ErrorCode.Good == status) { m_readCompleteCallback.AddRequestCache(transactionId, symbolNameList); } if (m_readCompleteCallback != null) m_readCompleteCallback.Unlock(); return status; } public uint Write(string symbolName, DataItem_t dataItem, ref uint result) { if (null == symbolName || null == dataItem) return ErrorCode.InvalidArgument; var addressList = new string[1] { symbolName }; var dataItemList = new DataItem_t[1] { dataItem }; uint[] resultList = null; var status = Write(addressList, dataItemList, ref resultList); if (ErrorCode.Good == status) result = resultList[0]; return status; } public uint Write(string[] symbolNameList, DataItem_t[] dataItemList, ref uint[] resultList) { if (null == symbolNameList || null == dataItemList) return ErrorCode.InvalidArgument; if (0 == symbolNameList.Length) return ErrorCode.NothingToDo; if (symbolNameList.Length != dataItemList.Length) return ErrorCode.InvalidArgument; IDataItem4CSharp[] dataItemInternals = new IDataItem4CSharp[dataItemList.Length]; for (int index = 0; index < dataItemList.Length; index++) { dataItemInternals[index] = dataItemList[index] != null ? dataItemList[index].Internal : null; } resultList = new uint[symbolNameList.Length]; return m_client.Write(symbolNameList, dataItemInternals, resultList); } public void SetWriteAsyncCallback(IWriteCompleteCallback_t callback) { m_writeCompleteCallback = callback; } public uint WriteAsync(string[] symbolNameList, DataItem_t[] dataItemList) { if (null == symbolNameList || null == dataItemList) return ErrorCode.InvalidArgument; if (0 == symbolNameList.Length) return ErrorCode.NothingToDo; if (symbolNameList.Length != dataItemList.Length) return ErrorCode.InvalidArgument; IDataItem4CSharp[] dataItemInternals = new IDataItem4CSharp[dataItemList.Length]; for (int index = 0; index < dataItemList.Length; index++) { dataItemInternals[index] = dataItemList[index] != null ? dataItemList[index].Internal : null; } uint transactionId = 0; if (m_writeCompleteCallback != null) m_writeCompleteCallback.Lock(); uint status = m_client.WriteAsync(symbolNameList, dataItemInternals, m_writeCompleteCallback, ref transactionId); if (ErrorCode.Good == status) m_writeCompleteCallback.AddRequestCache(transactionId, symbolNameList); if (m_writeCompleteCallback != null) m_writeCompleteCallback.Unlock(); return status; } public void SetDataChangeCallback(IDataChangeCallback_t callback) { m_dataChangeCallback = callback; } public uint Subscribe(string[] symbolNameList, ref uint samplingInterval, ref uint publishingInterval, ref uint handler) { if (null == symbolNameList) return ErrorCode.InvalidArgument; if (0 == symbolNameList.Length) return ErrorCode.NothingToDo; return m_client.Subscribe(symbolNameList, m_dataChangeCallback, ref samplingInterval, ref publishingInterval, ref handler); } public uint Unsubscribe(uint handler) { return m_client.Unsubscribe(handler); } public uint ReadDeviceInfo(ref AXDeviceInfo_t axDeviceInfo) { var axClient = m_client as IAXClient4CSharp; if (null == axClient) return ErrorCode.NotSupported; DataValue_t dataValue = new DataValue_t(); string[] propertyNames = { "Name", "Address", "Vendor", "Version", "SeriesName", "SerialNumber", "DeviceID", "DeviceType", "ChannelNumber", "EncryptedCommunication", "Ethernet" }; IDataValue4CSharp[] propertyValues = new IDataValue4CSharp[propertyNames.Length]; for (uint index = 0; index < propertyValues.Length; index++) { propertyValues[index] = DataValueFactory4CSharp.Create(DType.Undefined, null); } var status = axClient.ReadDeviceProperties(propertyNames, propertyValues); if (status == ErrorCode.Good) { if (null == axDeviceInfo) axDeviceInfo = new AXDeviceInfo_t(); for (uint index = 0; index < propertyNames.Length; index++) { axDeviceInfo.Internal.SetValue(propertyNames[index], propertyValues[index]); } } for (uint index = 0; index < propertyValues.Length; index++) { DataValueFactory4CSharp.Destroy(propertyValues[index]); } return status; } public uint BrowseSymbol(string address, ref ArrayBase_t childSymbolNodes) { if (null == address) return ErrorCode.InvalidArgument; var axClient = m_client as IAXClient4CSharp; if (null == axClient) return ErrorCode.NotSupported; if (null == childSymbolNodes) childSymbolNodes = new ArrayBase_t(); return axClient.BrowseSymbol(address, null, childSymbolNodes.Internal); } public uint GetSymbolProperty(string address, ref SymbolNodeInfo_t symbolProperty) { if (null == address) return ErrorCode.InvalidArgument; var axClient = m_client as IAXClient4CSharp; if (null == axClient) return ErrorCode.NotSupported; if (null == symbolProperty) symbolProperty = new SymbolNodeInfo_t(); return axClient.GetSymbolProperty(address, symbolProperty.Internal); } public uint GetConnectionState(ref ConnectionState connState) { if (null == m_client) return ErrorCode.InvalidState; var outputArgument = new DataValue_t(DType.Int32); var state = m_client.DoCommand("GetConnectionState", null, outputArgument.Internal); if(ErrorCode.Good == state) { int intValue = 0; outputArgument.GetValue(ref intValue); connState = (ConnectionState)intValue; } outputArgument.Dispose(); return state; } public uint SetConnectionCallback(IConnectionCallback_t callback) { var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; return axClient2.SetConnectionCallback(callback); } public uint CreateGroup(string[] symbolNameList, ref uint groupId, ref uint[] resultList) { var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; resultList = new uint[symbolNameList.Length]; uint status = axClient2.CreateGroup(symbolNameList, ref groupId, resultList); if (ErrorCode.Good == status) { lock (m_locker) { m_symbolListCache.Add(groupId, symbolNameList); } } return status; } public uint GetSymbolCount(uint groupId, ref uint count) { var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; return axClient2.GetSymbolCount(groupId, ref count); } public uint GetSymbolAddress(uint groupId, uint index, ref string address) { var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; return axClient2.GetSymbolAddress(groupId, index, ref address); } public uint DeleteGroup(uint groupId) { var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; uint status = axClient2.DeleteGroup(groupId); if (ErrorCode.Good == status) { lock (m_locker) { m_symbolListCache.Remove(groupId); } } return status; } public uint Read(uint groupId, ref DataItem_t[] dataItemList) { var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; uint count = 0; uint status = axClient2.GetSymbolCount(groupId, ref count); if (status != ErrorCode.Good) return status; if (dataItemList is null) dataItemList = new DataItem_t[count]; IDataItem4CSharp[] dataItemInternals = new IDataItem4CSharp[dataItemList.Length]; for (int index = 0; index < dataItemList.Length; index++) { if (dataItemList[index] is null) dataItemList[index] = new DataItem_t(); dataItemInternals[index] = dataItemList[index].Internal; } return axClient2.Read(groupId, dataItemInternals); } public uint ReadAsync(uint groupId) { var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; string[] symbolNameList = null; lock (m_locker) { if (!m_symbolListCache.ContainsKey(groupId)) return ErrorCode.NotFound; symbolNameList = m_symbolListCache[groupId]; } uint transactionId = 0; if (m_readCompleteCallback != null) m_readCompleteCallback.Lock(); uint status = axClient2.ReadAsync(groupId, m_readCompleteCallback, ref transactionId); if (ErrorCode.Good == status) { m_readCompleteCallback.AddRequestCache(transactionId, symbolNameList); } if (m_readCompleteCallback != null) m_readCompleteCallback.Unlock(); return status; } public uint Write(uint groupId, DataItem_t[] dataItemList, ref uint[] resultList) { if (null == dataItemList) return ErrorCode.InvalidArgument; var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; uint count = 0; uint status = axClient2.GetSymbolCount(groupId, ref count); if (status != ErrorCode.Good) return status; if (dataItemList.Length != count) return ErrorCode.InvalidArgument; IDataItem4CSharp[] dataItemInternals = new IDataItem4CSharp[dataItemList.Length]; for (int index = 0; index < dataItemList.Length; index++) { dataItemInternals[index] = dataItemList[index] != null ? dataItemList[index].Internal : null; } resultList = new uint[dataItemList.Length]; return axClient2.Write(groupId, dataItemInternals, resultList); } public uint WriteAsync(uint groupId, DataItem_t[] dataItemList) { if (null == dataItemList) return ErrorCode.InvalidArgument; var axClient2 = m_client as IAXClient24CSharp; if (null == axClient2) return ErrorCode.NotSupported; string[] symbolNameList = null; lock (m_locker) { if (!m_symbolListCache.ContainsKey(groupId)) return ErrorCode.NotFound; symbolNameList = m_symbolListCache[groupId]; } if (symbolNameList.Length != dataItemList.Length) return ErrorCode.InvalidArgument; IDataItem4CSharp[] dataItemInternals = new IDataItem4CSharp[dataItemList.Length]; for (int index = 0; index < dataItemList.Length; index++) { dataItemInternals[index] = dataItemList[index] != null ? dataItemList[index].Internal : null; } uint transactionId = 0; if (m_writeCompleteCallback != null) m_writeCompleteCallback.Lock(); uint status = axClient2.WriteAsync(groupId, dataItemInternals, m_writeCompleteCallback, ref transactionId); m_writeCompleteCallback.AddRequestCache(transactionId, symbolNameList); if (m_writeCompleteCallback != null) m_writeCompleteCallback.Unlock(); return status; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposeManaged) { if (!m_disposed) { if (disposeManaged) { //do nothing } CommClientManager.DestroyClient(m_client); m_client = null; m_disposed = true; } } private static ICommClientManager4CSharp CommClientManager { get { if (!IACommService_t.IsInitialised) { IACommService_t.Initialise(); } IIACommService4CSharp commService = IACommService_t.Instance(); return commService != null ? commService.ClientManager() : null; } } } }