using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; namespace EGFramework{ /// /// This class is not a simple protocol tools,only support sample functions to easy use. /// public class EGModbus : IEGFramework, IModule { public ConcurrentQueue RTUCache = new ConcurrentQueue(); public ConcurrentQueue TCPCache = new ConcurrentQueue(); public int Delay = 2000; public ConcurrentQueue WaitForSendRTU = new ConcurrentQueue(); public int NextSendRTU = 0; public int SendPointerRTU = 1; public ConcurrentQueue WaitForSendTCP = new ConcurrentQueue(); public int NextSendTCP = 0; public int SendPointerTCP = 1; public EasyEvent OnReadTimeOut = new EasyEvent(); public void Init() { this.EGRegisterMessageEvent((e,sender,ProtocolType)=>{ if(ProtocolType == ProtocolType.SerialPort){ RTUCache.Enqueue(e); } }); this.EGRegisterMessageEvent((e,sender,ProtocolType)=>{ if(ProtocolType == ProtocolType.TCPClient){ TCPCache.Enqueue(e); } }); this.EGOnMessage(); this.EGOnMessage(); } #region Modbus RTU Operations private bool IsRequestRTU { set; get; } public async Task ReadRTUAsync(ModbusRegisterType registerType,string serialPort,byte deviceAddress,ushort start,ushort count){ if(IsRequestRTU){ SendPointerRTU++; int messageId = SendPointerRTU; WaitForSendRTU.Enqueue(messageId); await Task.Run(async () => { while (IsRequestRTU || NextSendRTU != messageId) { await Task.Delay(10); //break; } }); EG.Print("-----Read"+messageId+" ----"); //return null; } RTUCache.Clear(); IsRequestRTU = true; IRequest ReadRequest; ModbusRTU_Response? res = null; switch(registerType){ case ModbusRegisterType.Coil: ReadRequest = new ModbusRTU_ReadCoils(deviceAddress,start,count); this.EGSendMessage(ReadRequest,serialPort,ProtocolType.SerialPort); this.EGSerialPort().SetExpectReceivedDataLength(6+count/8); break; case ModbusRegisterType.DiscreteInput: ReadRequest = new ModbusRTU_ReadDiscreteInput(deviceAddress,start,count); this.EGSendMessage(ReadRequest,serialPort,ProtocolType.SerialPort); this.EGSerialPort().SetExpectReceivedDataLength(6+count/8); break; case ModbusRegisterType.HoldingRegister: ReadRequest = new ModbusRTU_ReadHoldingRegisters(deviceAddress,start,count); this.EGSendMessage(ReadRequest,serialPort,ProtocolType.SerialPort); this.EGSerialPort().SetExpectReceivedDataLength(5+count*2); break; case ModbusRegisterType.InputRegisters: ReadRequest = new ModbusRTU_ReadInputRegisters(deviceAddress,start,count); this.EGSendMessage(ReadRequest,serialPort,ProtocolType.SerialPort); this.EGSerialPort().SetExpectReceivedDataLength(5+count*2); break; } await Task.Run(async ()=>{ int timeout = 0; while(RTUCache.Count==0 && timeout < Delay){ await Task.Delay(10); timeout+=10; } if(RTUCache.Count>0){ RTUCache.TryDequeue(out res); }else{ //Print Error Timeout OnReadTimeOut.Invoke(); } }); this.EGSerialPort().ClearReceivedCache(serialPort); IsRequestRTU = false; if(this.WaitForSendRTU.Count>0){ this.WaitForSendRTU.TryDequeue(out NextSendRTU); } return res; } public async Task WriteOnceRTUAsync(ModbusRegisterType registerType,string serialPort,byte deviceAddress,ushort registerAddress,object value){ if(IsRequestRTU){ SendPointerRTU++; int messageId = SendPointerRTU; WaitForSendRTU.Enqueue(messageId); await Task.Run(async () => { while (IsRequestRTU || NextSendRTU != messageId) { await Task.Delay(10); //break; } }); EG.Print("-----Write"+messageId+" ----"); //return null; } RTUCache.Clear(); IsRequestRTU = true; IRequest WriteRequest; ModbusRTU_Response? res = null; switch(registerType){ case ModbusRegisterType.Coil: WriteRequest = new ModbusRTU_WriteSingleCoil(deviceAddress,registerAddress,(bool)value); this.EGSendMessage(WriteRequest,serialPort,ProtocolType.SerialPort); this.EGSerialPort().SetExpectReceivedDataLength(WriteRequest.ToProtocolByteData().Length); break; case ModbusRegisterType.HoldingRegister: WriteRequest = new ModbusRTU_WriteSingleHoldingRegister(deviceAddress,registerAddress,(ushort)value); this.EGSendMessage(WriteRequest,serialPort,ProtocolType.SerialPort); this.EGSerialPort().SetExpectReceivedDataLength(WriteRequest.ToProtocolByteData().Length); break; } await Task.Run(async ()=>{ int timeout = 0; while(RTUCache.Count==0 && timeout < Delay){ await Task.Delay(10); timeout+=10; } if(RTUCache.Count>0){ RTUCache.TryDequeue(out res); }else{ //Print Error Timeout OnReadTimeOut.Invoke(); } }); this.EGSerialPort().ClearReceivedCache(serialPort); IsRequestRTU = false; if(this.WaitForSendRTU.Count>0){ this.WaitForSendRTU.TryDequeue(out NextSendRTU); } return res; } #endregion #region Modbus TCP Operations private bool IsRequestTCP { set; get; } public async Task ReadTCPAsync(ModbusRegisterType registerType,string ipPort,byte deviceAddress,ushort start,ushort count){ if(IsRequestTCP){ SendPointerTCP++; int messageId = SendPointerTCP; WaitForSendTCP.Enqueue(messageId); await Task.Run(async () => { while (IsRequestTCP || NextSendTCP != messageId) { await Task.Delay(10); //break; } }); EG.Print("-----Read"+messageId+" ----"); //return null; } TCPCache.Clear(); IsRequestTCP = true; IRequest ReadRequest; ModbusTCP_Response? res = null; switch(registerType){ case ModbusRegisterType.HoldingRegister: ReadRequest = new ModbusTCP_ReadHoldingRegisters(deviceAddress,start,count); // this.AppendMessage("【发送-"+DataModbusItem.SerialPort+"】 "+ReadRequest.ToProtocolByteData().ToStringByHex()); this.EGSendMessage(ReadRequest,ipPort,ProtocolType.TCPClient); break; } await Task.Run(async ()=>{ int timeout = 0; while(TCPCache.Count == 0 && timeout < Delay){ await Task.Delay(10); timeout += 10; } if(TCPCache.Count>0){ TCPCache.TryDequeue(out res); }else{ //Print Error Timeout OnReadTimeOut.Invoke(); } }); IsRequestTCP = false; if(this.WaitForSendTCP.Count>0){ this.WaitForSendTCP.TryDequeue(out NextSendTCP); } return res; } public async Task WriteOnceTCPAsync(ModbusRegisterType registerType,string ipPort,byte deviceAddress,ushort registerAddress,object value){ if(IsRequestTCP){ SendPointerTCP++; int messageId = SendPointerTCP; WaitForSendTCP.Enqueue(messageId); await Task.Run(async () => { while (IsRequestTCP || NextSendTCP != messageId) { await Task.Delay(10); //break; } }); EG.Print("-----Write"+messageId+" ----"); //return null; } TCPCache.Clear(); IsRequestTCP = true; IRequest WriteRequest; ModbusTCP_Response? res = null; switch(registerType){ case ModbusRegisterType.Coil: WriteRequest = new ModbusTCP_WriteSingleCoil(deviceAddress,registerAddress,(bool)value); this.EGSendMessage(WriteRequest,ipPort,ProtocolType.TCPClient); break; case ModbusRegisterType.HoldingRegister: if(value.GetType() == typeof(float)){ ushort[] writeData = ((float)value).ToByteArrayBigEndian().ToUShortArray(); WriteRequest = new ModbusTCP_WriteMultiHoldingRegister(deviceAddress,registerAddress,writeData); }else{ WriteRequest = new ModbusTCP_WriteSingleHoldingRegister(deviceAddress,registerAddress,(ushort)value); } this.EGSendMessage(WriteRequest,ipPort,ProtocolType.TCPClient); break; } await Task.Run(async ()=>{ int timeout = 0; while(TCPCache.Count==0 && timeout < Delay){ await Task.Delay(10); timeout+=10; } if(TCPCache.Count>0){ TCPCache.TryDequeue(out res); }else{ //Print Error Timeout OnReadTimeOut.Invoke(); } }); IsRequestTCP = false; if(this.WaitForSendTCP.Count>0){ this.WaitForSendTCP.TryDequeue(out NextSendTCP); } if(this.WaitForSendTCP.Count>0){ this.WaitForSendTCP.TryDequeue(out NextSendTCP); } return res; } #endregion public IArchitecture GetArchitecture() { return EGArchitectureImplement.Interface; } } public static class CanGetEGModbusExtension{ public static EGModbus EGModbus(this IEGFramework self){ return self.GetModule(); } } }