-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Vincent Wilms
committed
Oct 3, 2024
1 parent
39b4a9e
commit f2d74c6
Showing
45 changed files
with
6,076 additions
and
6,118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,171 +1,170 @@ | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace FluentModbus.SampleMaster | ||
namespace FluentModbus.SampleMaster; | ||
|
||
class Program | ||
{ | ||
class Program | ||
static async Task Main(string[] args) | ||
{ | ||
static async Task Main(string[] args) | ||
/* Modbus RTU uses a COM port for communication. Therefore, to run | ||
* this sample, you need to make sure that there are real or virtual | ||
* COM ports available. The easiest way is to install one of the free | ||
* COM port bridges available in the internet. That way, the Modbus | ||
* server can connect to e.g. COM1 which is virtually linked to COM2, | ||
* where the client is connected to. | ||
* | ||
* When you only want to use the client and communicate to an external | ||
* Modbus server, simply remove all server related code parts in this | ||
* sample and connect to real COM port using only the client. | ||
*/ | ||
|
||
/* define COM ports */ | ||
var serverPort = "COM1"; | ||
var clientPort = "COM2"; | ||
|
||
/* create logger */ | ||
var loggerFactory = LoggerFactory.Create(loggingBuilder => | ||
{ | ||
/* Modbus RTU uses a COM port for communication. Therefore, to run | ||
* this sample, you need to make sure that there are real or virtual | ||
* COM ports available. The easiest way is to install one of the free | ||
* COM port bridges available in the internet. That way, the Modbus | ||
* server can connect to e.g. COM1 which is virtually linked to COM2, | ||
* where the client is connected to. | ||
* | ||
* When you only want to use the client and communicate to an external | ||
* Modbus server, simply remove all server related code parts in this | ||
* sample and connect to real COM port using only the client. | ||
*/ | ||
|
||
/* define COM ports */ | ||
var serverPort = "COM1"; | ||
var clientPort = "COM2"; | ||
|
||
/* create logger */ | ||
var loggerFactory = LoggerFactory.Create(loggingBuilder => | ||
{ | ||
loggingBuilder.SetMinimumLevel(LogLevel.Debug); | ||
loggingBuilder.AddConsole(); | ||
}); | ||
loggingBuilder.SetMinimumLevel(LogLevel.Debug); | ||
loggingBuilder.AddConsole(); | ||
}); | ||
|
||
var serverLogger = loggerFactory.CreateLogger("Server"); | ||
var clientLogger = loggerFactory.CreateLogger("Client"); | ||
var serverLogger = loggerFactory.CreateLogger("Server"); | ||
var clientLogger = loggerFactory.CreateLogger("Client"); | ||
|
||
/* create Modbus RTU server */ | ||
using var server = new ModbusRtuServer(unitIdentifier: 1) | ||
{ | ||
// see 'RegistersChanged' event below | ||
EnableRaisingEvents = true | ||
}; | ||
/* create Modbus RTU server */ | ||
using var server = new ModbusRtuServer(unitIdentifier: 1) | ||
{ | ||
// see 'RegistersChanged' event below | ||
EnableRaisingEvents = true | ||
}; | ||
|
||
/* subscribe to the 'RegistersChanged' event (in case you need it) */ | ||
server.RegistersChanged += (sender, registerAddresses) => | ||
{ | ||
// the variable 'registerAddresses' contains the unit ID and a list of modified register addresses | ||
}; | ||
/* subscribe to the 'RegistersChanged' event (in case you need it) */ | ||
server.RegistersChanged += (sender, registerAddresses) => | ||
{ | ||
// the variable 'registerAddresses' contains the unit ID and a list of modified register addresses | ||
}; | ||
|
||
/* create Modbus RTU client */ | ||
var client = new ModbusRtuClient(); | ||
/* create Modbus RTU client */ | ||
var client = new ModbusRtuClient(); | ||
|
||
/* run Modbus RTU server */ | ||
var cts = new CancellationTokenSource(); | ||
server.Start(serverPort); | ||
serverLogger.LogInformation("Server started."); | ||
/* run Modbus RTU server */ | ||
var cts = new CancellationTokenSource(); | ||
server.Start(serverPort); | ||
serverLogger.LogInformation("Server started."); | ||
|
||
var task_server = Task.Run(async () => | ||
var task_server = Task.Run(async () => | ||
{ | ||
while (!cts.IsCancellationRequested) | ||
{ | ||
while (!cts.IsCancellationRequested) | ||
// lock is required to synchronize buffer access between this application and the Modbus client | ||
lock (server.Lock) | ||
{ | ||
// lock is required to synchronize buffer access between this application and the Modbus client | ||
lock (server.Lock) | ||
{ | ||
DoServerWork(server); | ||
} | ||
|
||
// update server register content once per second | ||
await Task.Delay(TimeSpan.FromSeconds(1)); | ||
DoServerWork(server); | ||
} | ||
}, cts.Token); | ||
|
||
/* run Modbus RTU client */ | ||
var task_client = Task.Run(() => | ||
{ | ||
client.Connect(clientPort); | ||
// update server register content once per second | ||
await Task.Delay(TimeSpan.FromSeconds(1)); | ||
} | ||
}, cts.Token); | ||
|
||
try | ||
{ | ||
DoClientWork(client, clientLogger); | ||
} | ||
catch (Exception ex) | ||
{ | ||
clientLogger.LogError(ex.Message); | ||
} | ||
/* run Modbus RTU client */ | ||
var task_client = Task.Run(() => | ||
{ | ||
client.Connect(clientPort); | ||
|
||
client.Close(); | ||
try | ||
{ | ||
DoClientWork(client, clientLogger); | ||
} | ||
catch (Exception ex) | ||
{ | ||
clientLogger.LogError(ex.Message); | ||
} | ||
|
||
Console.WriteLine("Tests finished. Press any key to continue."); | ||
Console.ReadKey(intercept: true); | ||
}); | ||
client.Close(); | ||
|
||
// wait for client task to finish | ||
await task_client; | ||
Console.WriteLine("Tests finished. Press any key to continue."); | ||
Console.ReadKey(intercept: true); | ||
}); | ||
|
||
// stop server | ||
cts.Cancel(); | ||
await task_server; | ||
// wait for client task to finish | ||
await task_client; | ||
|
||
server.Stop(); | ||
serverLogger.LogInformation("Server stopped."); | ||
} | ||
// stop server | ||
cts.Cancel(); | ||
await task_server; | ||
|
||
static void DoServerWork(ModbusRtuServer server) | ||
{ | ||
var random = new Random(); | ||
server.Stop(); | ||
serverLogger.LogInformation("Server stopped."); | ||
} | ||
|
||
// Option A: normal performance version, more flexibility | ||
static void DoServerWork(ModbusRtuServer server) | ||
{ | ||
var random = new Random(); | ||
|
||
/* get buffer in standard form (Span<short>) */ | ||
var registers = server.GetHoldingRegisters(); | ||
registers.SetLittleEndian<int>(address: 5, random.Next()); | ||
// Option A: normal performance version, more flexibility | ||
|
||
// Option B: high performance version, less flexibility | ||
/* get buffer in standard form (Span<short>) */ | ||
var registers = server.GetHoldingRegisters(); | ||
registers.SetLittleEndian<int>(address: 5, random.Next()); | ||
|
||
/* interpret buffer as array of bytes (8 bit) */ | ||
var byte_buffer = server.GetHoldingRegisterBuffer<byte>(); | ||
byte_buffer[20] = (byte)(random.Next() >> 24); | ||
// Option B: high performance version, less flexibility | ||
|
||
/* interpret buffer as array of shorts (16 bit) */ | ||
var short_buffer = server.GetHoldingRegisterBuffer<short>(); | ||
short_buffer[30] = (short)(random.Next(0, 100) >> 16); | ||
/* interpret buffer as array of bytes (8 bit) */ | ||
var byte_buffer = server.GetHoldingRegisterBuffer<byte>(); | ||
byte_buffer[20] = (byte)(random.Next() >> 24); | ||
|
||
/* interpret buffer as array of ints (32 bit) */ | ||
var int_buffer = server.GetHoldingRegisterBuffer<int>(); | ||
int_buffer[40] = random.Next(0, 100); | ||
} | ||
/* interpret buffer as array of shorts (16 bit) */ | ||
var short_buffer = server.GetHoldingRegisterBuffer<short>(); | ||
short_buffer[30] = (short)(random.Next(0, 100) >> 16); | ||
|
||
static void DoClientWork(ModbusRtuClient client, ILogger logger) | ||
{ | ||
Span<byte> data; | ||
|
||
var sleepTime = TimeSpan.FromMilliseconds(100); | ||
var unitIdentifier = 0x01; | ||
var startingAddress = 0; | ||
var registerAddress = 0; | ||
|
||
// ReadHoldingRegisters = 0x03, // FC03 | ||
data = client.ReadHoldingRegisters<byte>(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC03 - ReadHoldingRegisters: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// WriteMultipleRegisters = 0x10, // FC16 | ||
client.WriteMultipleRegisters(unitIdentifier, startingAddress, new byte[] { 10, 00, 20, 00, 30, 00, 255, 00, 255, 01 }); | ||
logger.LogInformation("FC16 - WriteMultipleRegisters: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// ReadCoils = 0x01, // FC01 | ||
data = client.ReadCoils(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC01 - ReadCoils: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// ReadDiscreteInputs = 0x02, // FC02 | ||
data = client.ReadDiscreteInputs(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC02 - ReadDiscreteInputs: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// ReadInputRegisters = 0x04, // FC04 | ||
data = client.ReadInputRegisters<byte>(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC04 - ReadInputRegisters: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// WriteSingleCoil = 0x05, // FC05 | ||
client.WriteSingleCoil(unitIdentifier, registerAddress, true); | ||
logger.LogInformation("FC05 - WriteSingleCoil: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// WriteSingleRegister = 0x06, // FC06 | ||
client.WriteSingleRegister(unitIdentifier, registerAddress, 127); | ||
logger.LogInformation("FC06 - WriteSingleRegister: Done"); | ||
} | ||
/* interpret buffer as array of ints (32 bit) */ | ||
var int_buffer = server.GetHoldingRegisterBuffer<int>(); | ||
int_buffer[40] = random.Next(0, 100); | ||
} | ||
|
||
static void DoClientWork(ModbusRtuClient client, ILogger logger) | ||
{ | ||
Span<byte> data; | ||
|
||
var sleepTime = TimeSpan.FromMilliseconds(100); | ||
var unitIdentifier = 0x01; | ||
var startingAddress = 0; | ||
var registerAddress = 0; | ||
|
||
// ReadHoldingRegisters = 0x03, // FC03 | ||
data = client.ReadHoldingRegisters<byte>(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC03 - ReadHoldingRegisters: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// WriteMultipleRegisters = 0x10, // FC16 | ||
client.WriteMultipleRegisters(unitIdentifier, startingAddress, new byte[] { 10, 00, 20, 00, 30, 00, 255, 00, 255, 01 }); | ||
logger.LogInformation("FC16 - WriteMultipleRegisters: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// ReadCoils = 0x01, // FC01 | ||
data = client.ReadCoils(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC01 - ReadCoils: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// ReadDiscreteInputs = 0x02, // FC02 | ||
data = client.ReadDiscreteInputs(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC02 - ReadDiscreteInputs: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// ReadInputRegisters = 0x04, // FC04 | ||
data = client.ReadInputRegisters<byte>(unitIdentifier, startingAddress, 10); | ||
logger.LogInformation("FC04 - ReadInputRegisters: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// WriteSingleCoil = 0x05, // FC05 | ||
client.WriteSingleCoil(unitIdentifier, registerAddress, true); | ||
logger.LogInformation("FC05 - WriteSingleCoil: Done"); | ||
Thread.Sleep(sleepTime); | ||
|
||
// WriteSingleRegister = 0x06, // FC06 | ||
client.WriteSingleRegister(unitIdentifier, registerAddress, 127); | ||
logger.LogInformation("FC06 - WriteSingleRegister: Done"); | ||
} | ||
} |
Oops, something went wrong.