You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
12 KiB
280 lines
12 KiB
1 year ago
|
using System;
|
||
4 months ago
|
using System.Collections.Concurrent;
|
||
1 year ago
|
using System.Collections.Generic;
|
||
|
using System.Threading.Tasks;
|
||
|
|
||
|
namespace EGFramework{
|
||
|
/// <summary>
|
||
|
/// This class is not a simple protocol tools,only support sample functions to easy use.
|
||
|
/// </summary>
|
||
|
public class EGModbus : IEGFramework, IModule
|
||
|
{
|
||
4 months ago
|
public ConcurrentQueue<ModbusRTU_Response?> RTUCache = new ConcurrentQueue<ModbusRTU_Response?>();
|
||
|
public ConcurrentQueue<ModbusTCP_Response?> TCPCache = new ConcurrentQueue<ModbusTCP_Response?>();
|
||
1 year ago
|
|
||
|
public int Delay = 2000;
|
||
|
|
||
4 months ago
|
public ConcurrentQueue<int> WaitForSendRTU = new ConcurrentQueue<int>();
|
||
1 year ago
|
public int NextSendRTU = 0;
|
||
|
public int SendPointerRTU = 1;
|
||
|
|
||
4 months ago
|
public ConcurrentQueue<int> WaitForSendTCP = new ConcurrentQueue<int>();
|
||
1 year ago
|
public int NextSendTCP = 0;
|
||
|
public int SendPointerTCP = 1;
|
||
|
|
||
1 year ago
|
public EasyEvent OnReadTimeOut = new EasyEvent();
|
||
|
|
||
|
public void Init()
|
||
|
{
|
||
|
this.EGRegisterMessageEvent<ModbusRTU_Response>((e,sender,ProtocolType)=>{
|
||
|
if(ProtocolType == ProtocolType.SerialPort){
|
||
|
RTUCache.Enqueue(e);
|
||
|
}
|
||
|
});
|
||
|
this.EGRegisterMessageEvent<ModbusTCP_Response>((e,sender,ProtocolType)=>{
|
||
|
if(ProtocolType == ProtocolType.TCPClient){
|
||
|
TCPCache.Enqueue(e);
|
||
|
}
|
||
|
});
|
||
|
this.EGOnMessage<ModbusRTU_Response>();
|
||
|
this.EGOnMessage<ModbusTCP_Response>();
|
||
|
}
|
||
|
|
||
1 year ago
|
#region Modbus RTU Operations
|
||
1 year ago
|
private bool IsRequestRTU { set; get; }
|
||
1 year ago
|
public async Task<ModbusRTU_Response?> ReadRTUAsync(ModbusRegisterType registerType,string serialPort,byte deviceAddress,ushort start,ushort count){
|
||
1 year ago
|
if(IsRequestRTU){
|
||
1 year ago
|
SendPointerRTU++;
|
||
|
int messageId = SendPointerRTU;
|
||
|
WaitForSendRTU.Enqueue(messageId);
|
||
|
await Task.Run(async () =>
|
||
|
{
|
||
1 year ago
|
while (IsRequestRTU || NextSendRTU != messageId)
|
||
1 year ago
|
{
|
||
|
await Task.Delay(10);
|
||
|
//break;
|
||
|
}
|
||
|
});
|
||
5 months ago
|
EG.Print("-----Read"+messageId+" ----");
|
||
1 year ago
|
//return null;
|
||
|
}
|
||
|
RTUCache.Clear();
|
||
1 year ago
|
IsRequestRTU = true;
|
||
1 year ago
|
IRequest ReadRequest;
|
||
|
ModbusRTU_Response? res = null;
|
||
|
switch(registerType){
|
||
1 year ago
|
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;
|
||
1 year ago
|
case ModbusRegisterType.HoldingRegister:
|
||
|
ReadRequest = new ModbusRTU_ReadHoldingRegisters(deviceAddress,start,count);
|
||
|
this.EGSendMessage(ReadRequest,serialPort,ProtocolType.SerialPort);
|
||
1 year ago
|
this.EGSerialPort().SetExpectReceivedDataLength(5+count*2);
|
||
|
break;
|
||
|
case ModbusRegisterType.InputRegisters:
|
||
|
ReadRequest = new ModbusRTU_ReadInputRegisters(deviceAddress,start,count);
|
||
|
this.EGSendMessage(ReadRequest,serialPort,ProtocolType.SerialPort);
|
||
1 year ago
|
this.EGSerialPort().SetExpectReceivedDataLength(5+count*2);
|
||
1 year ago
|
break;
|
||
|
}
|
||
|
await Task.Run(async ()=>{
|
||
|
int timeout = 0;
|
||
|
while(RTUCache.Count==0 && timeout < Delay){
|
||
|
await Task.Delay(10);
|
||
|
timeout+=10;
|
||
|
}
|
||
|
if(RTUCache.Count>0){
|
||
4 months ago
|
RTUCache.TryDequeue(out res);
|
||
1 year ago
|
}else{
|
||
|
//Print Error Timeout
|
||
|
OnReadTimeOut.Invoke();
|
||
|
}
|
||
|
});
|
||
1 year ago
|
this.EGSerialPort().ClearReceivedCache(serialPort);
|
||
|
IsRequestRTU = false;
|
||
1 year ago
|
if(this.WaitForSendRTU.Count>0){
|
||
4 months ago
|
this.WaitForSendRTU.TryDequeue(out NextSendRTU);
|
||
1 year ago
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
1 year ago
|
public async Task<ModbusRTU_Response?> WriteOnceRTUAsync(ModbusRegisterType registerType,string serialPort,byte deviceAddress,ushort registerAddress,object value){
|
||
1 year ago
|
if(IsRequestRTU){
|
||
|
SendPointerRTU++;
|
||
|
int messageId = SendPointerRTU;
|
||
|
WaitForSendRTU.Enqueue(messageId);
|
||
|
await Task.Run(async () =>
|
||
|
{
|
||
|
while (IsRequestRTU || NextSendRTU != messageId)
|
||
|
{
|
||
|
await Task.Delay(10);
|
||
|
//break;
|
||
|
}
|
||
|
});
|
||
5 months ago
|
EG.Print("-----Write"+messageId+" ----");
|
||
1 year ago
|
//return null;
|
||
|
}
|
||
|
RTUCache.Clear();
|
||
|
IsRequestRTU = true;
|
||
1 year ago
|
IRequest WriteRequest;
|
||
1 year ago
|
ModbusRTU_Response? res = null;
|
||
|
switch(registerType){
|
||
1 year ago
|
case ModbusRegisterType.Coil:
|
||
|
WriteRequest = new ModbusRTU_WriteSingleCoil(deviceAddress,registerAddress,(bool)value);
|
||
|
this.EGSendMessage(WriteRequest,serialPort,ProtocolType.SerialPort);
|
||
|
this.EGSerialPort().SetExpectReceivedDataLength(WriteRequest.ToProtocolByteData().Length);
|
||
|
break;
|
||
1 year ago
|
case ModbusRegisterType.HoldingRegister:
|
||
1 year ago
|
WriteRequest = new ModbusRTU_WriteSingleHoldingRegister(deviceAddress,registerAddress,(ushort)value);
|
||
|
this.EGSendMessage(WriteRequest,serialPort,ProtocolType.SerialPort);
|
||
|
this.EGSerialPort().SetExpectReceivedDataLength(WriteRequest.ToProtocolByteData().Length);
|
||
1 year ago
|
break;
|
||
|
}
|
||
|
await Task.Run(async ()=>{
|
||
|
int timeout = 0;
|
||
|
while(RTUCache.Count==0 && timeout < Delay){
|
||
|
await Task.Delay(10);
|
||
|
timeout+=10;
|
||
|
}
|
||
|
if(RTUCache.Count>0){
|
||
4 months ago
|
RTUCache.TryDequeue(out res);
|
||
1 year ago
|
}else{
|
||
|
//Print Error Timeout
|
||
|
OnReadTimeOut.Invoke();
|
||
|
}
|
||
|
});
|
||
|
this.EGSerialPort().ClearReceivedCache(serialPort);
|
||
|
IsRequestRTU = false;
|
||
|
if(this.WaitForSendRTU.Count>0){
|
||
4 months ago
|
this.WaitForSendRTU.TryDequeue(out NextSendRTU);
|
||
1 year ago
|
}
|
||
|
return res;
|
||
|
}
|
||
1 year ago
|
|
||
|
#endregion
|
||
1 year ago
|
|
||
1 year ago
|
#region Modbus TCP Operations
|
||
1 year ago
|
private bool IsRequestTCP { set; get; }
|
||
1 year ago
|
public async Task<ModbusTCP_Response?> ReadTCPAsync(ModbusRegisterType registerType,string ipPort,byte deviceAddress,ushort start,ushort count){
|
||
1 year ago
|
if(IsRequestTCP){
|
||
1 year ago
|
SendPointerTCP++;
|
||
|
int messageId = SendPointerTCP;
|
||
|
WaitForSendTCP.Enqueue(messageId);
|
||
1 year ago
|
await Task.Run(async () =>
|
||
|
{
|
||
1 year ago
|
while (IsRequestTCP || NextSendTCP != messageId)
|
||
1 year ago
|
{
|
||
|
await Task.Delay(10);
|
||
|
//break;
|
||
|
}
|
||
|
});
|
||
5 months ago
|
EG.Print("-----Read"+messageId+" ----");
|
||
1 year ago
|
//return null;
|
||
|
}
|
||
|
TCPCache.Clear();
|
||
1 year ago
|
IsRequestTCP = true;
|
||
1 year ago
|
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){
|
||
4 months ago
|
TCPCache.TryDequeue(out res);
|
||
1 year ago
|
}else{
|
||
|
//Print Error Timeout
|
||
|
OnReadTimeOut.Invoke();
|
||
|
}
|
||
|
});
|
||
1 year ago
|
IsRequestTCP = false;
|
||
1 year ago
|
if(this.WaitForSendTCP.Count>0){
|
||
4 months ago
|
this.WaitForSendTCP.TryDequeue(out NextSendTCP);
|
||
1 year ago
|
}
|
||
1 year ago
|
return res;
|
||
|
}
|
||
1 year ago
|
|
||
1 year ago
|
public async Task<ModbusTCP_Response?> WriteOnceTCPAsync(ModbusRegisterType registerType,string ipPort,byte deviceAddress,ushort registerAddress,object value){
|
||
1 year ago
|
if(IsRequestTCP){
|
||
|
SendPointerTCP++;
|
||
|
int messageId = SendPointerTCP;
|
||
|
WaitForSendTCP.Enqueue(messageId);
|
||
|
await Task.Run(async () =>
|
||
|
{
|
||
|
while (IsRequestTCP || NextSendTCP != messageId)
|
||
|
{
|
||
|
await Task.Delay(10);
|
||
|
//break;
|
||
|
}
|
||
|
});
|
||
5 months ago
|
EG.Print("-----Write"+messageId+" ----");
|
||
1 year ago
|
//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);
|
||
1 year ago
|
this.EGSendMessage(WriteRequest,ipPort,ProtocolType.TCPClient);
|
||
1 year ago
|
break;
|
||
|
case ModbusRegisterType.HoldingRegister:
|
||
1 year ago
|
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);
|
||
|
}
|
||
1 year ago
|
this.EGSendMessage(WriteRequest,ipPort,ProtocolType.TCPClient);
|
||
1 year ago
|
break;
|
||
|
}
|
||
|
await Task.Run(async ()=>{
|
||
|
int timeout = 0;
|
||
|
while(TCPCache.Count==0 && timeout < Delay){
|
||
|
await Task.Delay(10);
|
||
|
timeout+=10;
|
||
|
}
|
||
|
if(TCPCache.Count>0){
|
||
4 months ago
|
TCPCache.TryDequeue(out res);
|
||
1 year ago
|
}else{
|
||
|
//Print Error Timeout
|
||
|
OnReadTimeOut.Invoke();
|
||
|
}
|
||
|
});
|
||
|
IsRequestTCP = false;
|
||
|
if(this.WaitForSendTCP.Count>0){
|
||
4 months ago
|
this.WaitForSendTCP.TryDequeue(out NextSendTCP);
|
||
1 year ago
|
}
|
||
|
if(this.WaitForSendTCP.Count>0){
|
||
4 months ago
|
this.WaitForSendTCP.TryDequeue(out NextSendTCP);
|
||
1 year ago
|
}
|
||
|
return res;
|
||
|
}
|
||
1 year ago
|
#endregion
|
||
1 year ago
|
public IArchitecture GetArchitecture()
|
||
|
{
|
||
|
return EGArchitectureImplement.Interface;
|
||
|
}
|
||
|
}
|
||
|
public static class CanGetEGModbusExtension{
|
||
|
public static EGModbus EGModbus(this IEGFramework self){
|
||
|
return self.GetModule<EGModbus>();
|
||
|
}
|
||
|
}
|
||
|
}
|