Skip to content

Commit

Permalink
Merge pull request #96 from helynranta/always-raise-changed
Browse files Browse the repository at this point in the history
Add option for raising event even if values of buffer have not changed
  • Loading branch information
Apollo3zehn authored Feb 20, 2024
2 parents e3e2634 + 654d2a1 commit bcddc39
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/FluentModbus/Client/ModbusClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public Span<byte> ReadCoils(int unitIdentifier, int startingAddress, int quantit
}

/// <summary>
/// Reads the specified number of discrete inputs as byte array. Each bit of the returned array represents a single discete input.
/// Reads the specified number of discrete inputs as byte array. Each bit of the returned array represents a single discrete input.
/// </summary>
/// <param name="unitIdentifier">The unit identifier is used to communicate via devices such as bridges, routers and gateways that use a single IP address to support multiple independent Modbus end units. Thus, the unit identifier is the address of a remote slave connected on a serial line or on other buses. Use the default values 0x00 or 0xFF when communicating to a Modbus server that is directly connected to a TCP/IP network.</param>
/// <param name="startingAddress">The discrete input start address for the read operation.</param>
Expand Down
28 changes: 20 additions & 8 deletions src/FluentModbus/Server/ModbusRequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,18 +187,30 @@ private void DetectChangedRegisters(int startingAddress, Span<short> oldValues,
{
Span<int> changedRegisters = stackalloc int[newValues.Length];

var index = 0;
var length = 0;

for (int i = 0; i < newValues.Length; i++)
if (ModbusServer.AlwaysRaiseChangedEvent)
{
if (newValues[i] != oldValues[i])
for (int i = 0; i < newValues.Length; i++)
{
changedRegisters[index] = startingAddress + i;
index++;
changedRegisters[length] = startingAddress + i;
length++;
}
}

ModbusServer.OnRegistersChanged(UnitIdentifier, changedRegisters.Slice(0, index).ToArray());
else
{
for (int i = 0; i < newValues.Length; i++)
{
if (newValues[i] != oldValues[i])
{
changedRegisters[length] = startingAddress + i;
length++;
}
}
}

ModbusServer.OnRegistersChanged(UnitIdentifier, changedRegisters.Slice(0, length).ToArray());
}

// class 0
Expand Down Expand Up @@ -352,7 +364,7 @@ private void ProcessWriteSingleCoil()

coils[bufferByteIndex] = newValue;

if (ModbusServer.EnableRaisingEvents && newValue != oldValue)
if (ModbusServer.EnableRaisingEvents && (newValue != oldValue || ModbusServer.AlwaysRaiseChangedEvent))
ModbusServer.OnCoilsChanged(UnitIdentifier, new int[] { outputAddress });

FrameBuffer.Writer.Write((byte)ModbusFunctionCode.WriteSingleCoil);
Expand All @@ -379,7 +391,7 @@ private void ProcessWriteSingleRegister()
var newValue = registerValue;
holdingRegisters[registerAddress] = newValue;

if (ModbusServer.EnableRaisingEvents && newValue != oldValue)
if (ModbusServer.EnableRaisingEvents && (newValue != oldValue || ModbusServer.AlwaysRaiseChangedEvent))
ModbusServer.OnRegistersChanged(UnitIdentifier, new int[] { registerAddress });

FrameBuffer.Writer.Write((byte)ModbusFunctionCode.WriteSingleRegister);
Expand Down
5 changes: 5 additions & 0 deletions src/FluentModbus/Server/ModbusServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ protected ModbusServer(bool isAsynchronous)
/// </summary>
public bool EnableRaisingEvents { get; set; }

/// <summary>
/// Trigger the RegistersChanged or CoilsChanged event even when value has not been updated. Default: false.
/// </summary>
public bool AlwaysRaiseChangedEvent { get; set; } = false;

internal bool IsSingleZeroUnitMode => UnitIdentifiers.Count == 1 && UnitIdentifiers[0] == 0;

private protected CancellationTokenSource CTS { get; private set; } = new CancellationTokenSource();
Expand Down
43 changes: 27 additions & 16 deletions tests/FluentModbus.Tests/ModbusServerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,12 @@ public void CanSetAndGetBigEndianInputRegisters()
}

[Theory]
[InlineData(true, false, true)]
[InlineData(false, true, true)]
[InlineData(false, false, false)]
[InlineData(true, true, false)]
public async Task CanDetectCoilChanged(bool initialValue, bool newValue, bool expected)
[InlineData(true, false, true, false)]
[InlineData(false, true, true, false)]
[InlineData(false, false, false, false)]
[InlineData(true, true, false, false)]
[InlineData(false, false, true, true)]
public async Task CanDetectCoilChanged(bool initialValue, bool newValue, bool expected, bool alwaysRaiseChangedEvent)
{
// Arrange
var actual = false;
Expand All @@ -319,7 +320,8 @@ public async Task CanDetectCoilChanged(bool initialValue, bool newValue, bool ex

using var server = new ModbusTcpServer()
{
EnableRaisingEvents = true
EnableRaisingEvents = true,
AlwaysRaiseChangedEvent = alwaysRaiseChangedEvent
};

server.GetCoils().Set(address, initialValue);
Expand All @@ -346,10 +348,11 @@ await Task.Run(() =>
}

[Theory]
[InlineData(99, 100, true)]
[InlineData(0, -1, true)]
[InlineData(1, 1, false)]
public async Task CanDetectRegisterChanged(short initialValue, short newValue, bool expected)
[InlineData(99, 100, true, false)]
[InlineData(0, -1, true, false)]
[InlineData(1, 1, false, false)]
[InlineData(0, 0, true, true)]
public async Task CanDetectRegisterChanged(short initialValue, short newValue, bool expected, bool alwaysRaiseChangedEvent)
{
// Arrange
var actual = false;
Expand All @@ -358,7 +361,8 @@ public async Task CanDetectRegisterChanged(short initialValue, short newValue, b

using var server = new ModbusTcpServer()
{
EnableRaisingEvents = true
EnableRaisingEvents = true,
AlwaysRaiseChangedEvent = alwaysRaiseChangedEvent
};

server.GetHoldingRegisters()[address] = initialValue;
Expand All @@ -385,9 +389,11 @@ await Task.Run(() =>
}

[Theory]
[InlineData(false, new short[] { 99, 101, 102 }, new short[] { 100, 101, 103 }, new bool[] { true, false, true })]
[InlineData(true, new short[] { 99, 101, 102 }, new short[] { 100, 101, 103 }, new bool[] { true, false, true })]
public async Task CanDetectRegistersChanged(bool useReadWriteMethod, short[] initialValues, short[] newValues, bool[] expected)
[InlineData(false, new short[] { 99, 101, 102 }, new short[] { 100, 101, 103 }, new bool[] { true, false, true }, false)]
[InlineData(true, new short[] { 99, 101, 102 }, new short[] { 100, 101, 103 }, new bool[] { true, false, true }, false)]
[InlineData(false, new short[] { 0, 0, 0 }, new short[] { 0, 0, 0 }, new bool[] { true, true, true }, true)]
[InlineData(true, new short[] { 0, 0, 0 }, new short[] { 0, 0, 0 }, new bool[] { true, true, true }, true)]
public async Task CanDetectRegistersChanged(bool useReadWriteMethod, short[] initialValues, short[] newValues, bool[] expected, bool alwaysRaiseChangedEvent)
{
// Arrange
var actual = new bool[3];
Expand All @@ -396,7 +402,8 @@ public async Task CanDetectRegistersChanged(bool useReadWriteMethod, short[] ini

using var server = new ModbusTcpServer()
{
EnableRaisingEvents = true
EnableRaisingEvents = true,
AlwaysRaiseChangedEvent = alwaysRaiseChangedEvent
};

for (int i = 0; i < initialValues.Length; i++)
Expand All @@ -406,7 +413,11 @@ public async Task CanDetectRegistersChanged(bool useReadWriteMethod, short[] ini

server.RegistersChanged += (sender, e) =>
{
Assert.True(e.Registers.Length == 2);
if (alwaysRaiseChangedEvent)
Assert.True(e.Registers.Length == 3);

else
Assert.True(e.Registers.Length == 2);

for (int i = 0; i < initialValues.Length; i++)
{
Expand Down

0 comments on commit bcddc39

Please sign in to comment.