Skip to content

Commit 0663922

Browse files
committed
Add logging to ModbusClient
- Add Logger property to port. - Replaced all calls wrapped with DEBUG with equivalents from ILogger. - Add new log debug calls in all exceptions and operations. - Update sample and readme accordingly. - Bumo version to 1.1.
1 parent 92599d4 commit 0663922

File tree

13 files changed

+179
-27
lines changed

13 files changed

+179
-27
lines changed

devices/Modbus/Client/ModbusClient.cs

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Iot.Device.Modbus.Protocol;
77
using Iot.Device.Modbus.Structures;
88
using Iot.Device.Modbus.Util;
9+
using Microsoft.Extensions.Logging;
910

1011
namespace Iot.Device.Modbus.Client
1112
{
@@ -54,9 +55,18 @@ public ModbusClient(
5455
/// <param name="startAddress">The starting address of the inputs.</param>
5556
/// <param name="count">The number of inputs to read.</param>
5657
/// <returns>An array of boolean values representing the state of the discrete inputs.</returns>
57-
public bool[] ReadDiscreteInputs(byte deviceId, ushort startAddress, ushort count)
58+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/>, <paramref name="startAddress"/>, or <paramref name="count"/> is out of range.</exception>
59+
public bool[] ReadDiscreteInputs(
60+
byte deviceId,
61+
ushort startAddress,
62+
ushort count)
5863
{
59-
var data = Read(deviceId, startAddress, count, FunctionCode.ReadDiscreteInputs);
64+
var data = Read(
65+
deviceId,
66+
startAddress,
67+
count,
68+
FunctionCode.ReadDiscreteInputs);
69+
6070
if (data != null)
6171
{
6272
var values = new bool[count];
@@ -67,11 +77,13 @@ public bool[] ReadDiscreteInputs(byte deviceId, ushort startAddress, ushort coun
6777
int posBit = i % 8;
6878

6979
int val = data[posByte] & (byte)Math.Pow(2, posBit);
80+
7081
var dinput = new DiscreteInput
7182
{
7283
Address = (ushort)(startAddress + i),
7384
Value = val > 0
7485
};
86+
7587
values[i] = dinput.Value;
7688
}
7789

@@ -90,6 +102,7 @@ public bool[] ReadDiscreteInputs(byte deviceId, ushort startAddress, ushort coun
90102
/// <param name="startAddress">The starting address of the registers.</param>
91103
/// <param name="count">The number of registers to read.</param>
92104
/// <returns>An array of ushort values representing the values of the input registers.</returns>
105+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/>, <paramref name="startAddress"/>, or <paramref name="count"/> is out of range.</exception>""
93106
public short[] ReadInputRegisters(
94107
byte deviceId,
95108
ushort startAddress,
@@ -132,7 +145,11 @@ public short[] ReadInputRegisters(
132145
/// <param name="startAddress">The starting address of the coils.</param>
133146
/// <param name="count">The number of coils to read.</param>
134147
/// <returns>An array of boolean values representing the state of the coils.</returns>
135-
public bool[] ReadCoils(byte deviceId, ushort startAddress, ushort count)
148+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/>, <paramref name="startAddress"/>, or <paramref name="count"/> is out of range.</exception>"
149+
public bool[] ReadCoils(
150+
byte deviceId,
151+
ushort startAddress,
152+
ushort count)
136153
{
137154
var data = Read(deviceId, startAddress, count, FunctionCode.ReadCoils);
138155

@@ -146,6 +163,7 @@ public bool[] ReadCoils(byte deviceId, ushort startAddress, ushort count)
146163
int posBit = i % 8;
147164

148165
int val = data[posByte] & (byte)Math.Pow(2, posBit);
166+
149167
var coil = new Coil
150168
{
151169
Address = (ushort)(startAddress + i),
@@ -170,6 +188,7 @@ public bool[] ReadCoils(byte deviceId, ushort startAddress, ushort count)
170188
/// <param name="startAddress">The starting address of the registers.</param>
171189
/// <param name="count">The number of registers to read.</param>
172190
/// <returns>An array of ushort values representing the values of the holding registers.</returns>
191+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/>, <paramref name="startAddress"/>, or <paramref name="count"/> is out of range.</exception>"
173192
public short[] ReadHoldingRegisters(
174193
byte deviceId,
175194
ushort startAddress,
@@ -212,9 +231,17 @@ private byte[] Read(byte deviceId, ushort startAddress, ushort count, FunctionCo
212231
function != FunctionCode.ReadHoldingRegisters &&
213232
function != FunctionCode.ReadInputRegisters)
214233
{
215-
throw new ArgumentException(nameof(function));
234+
Logger?.LogError("Invalid function for Read: {0}", function.ToNameString());
235+
throw new ArgumentException();
216236
}
217237

238+
Logger?.LogDebug(
239+
"Reading {0} from Device ID {1}, Start Address {2}, Count {3}",
240+
function.ToNameString(),
241+
deviceId,
242+
startAddress,
243+
count);
244+
218245
switch (function)
219246
{
220247
case FunctionCode.ReadCoils:
@@ -232,7 +259,7 @@ private byte[] Read(byte deviceId, ushort startAddress, ushort count, FunctionCo
232259
break;
233260
}
234261

235-
var response = this.SendRequest(new Request
262+
var response = SendRequest(new Request
236263
{
237264
DeviceId = deviceId,
238265
Function = function,
@@ -263,7 +290,11 @@ private byte[] Read(byte deviceId, ushort startAddress, ushort count, FunctionCo
263290
/// <param name="startAddress">The address of the coil to write.</param>
264291
/// <param name="value">The value to write to the coil.</param>
265292
/// <returns><see langword="true"/> if the write operation is successful, <see langword="false"/> otherwise.</returns>
266-
public bool WriteSingleCoil(byte deviceId, ushort startAddress, bool value)
293+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/> or <paramref name="startAddress"/> is out of range.</exception>
294+
public bool WriteSingleCoil(
295+
byte deviceId,
296+
ushort startAddress,
297+
bool value)
267298
{
268299
var buffer = new DataBuffer(2);
269300
buffer.Set(0, (ushort)(value ? 0xFF00 : 0x0000));
@@ -278,6 +309,7 @@ public bool WriteSingleCoil(byte deviceId, ushort startAddress, bool value)
278309
/// <param name="startAddress">The address of the register to write.</param>
279310
/// <param name="value">The value to write to the register.</param>
280311
/// <returns><see langword="true"/> if the write operation is successful, <see langword="false"/> otherwise.</returns>
312+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/> or <paramref name="startAddress"/> is out of range.</exception>
281313
public bool WriteSingleRegister(
282314
byte deviceId,
283315
ushort startAddress,
@@ -301,14 +333,16 @@ public bool WriteSingleRegister(
301333
/// <param name="startAddress">The starting address of the coils to write.</param>
302334
/// <param name="values">An array of boolean values representing the state of the coils to write.</param>
303335
/// <returns><see langword="true"/> if the write operation is successful, <see langword="false"/> otherwise.</returns>
336+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/> or <paramref name="startAddress"/> is out of range, or the length of the <paramref name="values"/> array is zero.</exception>
304337
public bool WriteMultipleCoils(
305338
byte deviceId,
306339
ushort startAddress,
307340
bool[] values)
308341
{
309342
if (values.Length == 0)
310343
{
311-
throw new ArgumentOutOfRangeException(nameof(values));
344+
Logger?.LogError("Invalid length: {0}", values.Length);
345+
throw new ArgumentOutOfRangeException();
312346
}
313347

314348
int numBytes = (int)Math.Ceiling(values.Length / 8.0);
@@ -343,14 +377,16 @@ public bool WriteMultipleCoils(
343377
/// <param name="startAddress">The starting address of the registers to write.</param>
344378
/// <param name="values">An array of ushort values representing the values to write to the registers.</param>
345379
/// <returns><see langword="true"/> if the write operation is successful, <see langword="false"/> otherwise.</returns>
380+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="deviceId"/> or <paramref name="startAddress"/> is out of range, or the length of the <paramref name="values"/> array is zero.</exception>
346381
public bool WriteMultipleRegisters(
347382
byte deviceId,
348383
ushort startAddress,
349384
ushort[] values)
350385
{
351386
if (values.Length == 0)
352387
{
353-
throw new ArgumentOutOfRangeException(nameof(values));
388+
Logger?.LogError("Invalid length: {0}", values.Length);
389+
throw new ArgumentOutOfRangeException();
354390
}
355391

356392
var buffer = new DataBuffer((values.Length * 2) + 1);
@@ -384,7 +420,8 @@ private bool Write(
384420
function != FunctionCode.WriteMultipleCoils &&
385421
function != FunctionCode.WriteMultipleRegisters)
386422
{
387-
throw new ArgumentException(nameof(function));
423+
Logger?.LogError("Invalid function for Write: {0}", function.ToNameString());
424+
throw new ArgumentException();
388425
}
389426

390427
if (count > 0)
@@ -421,6 +458,7 @@ private bool Write(
421458
};
422459

423460
var response = SendRequest(request);
461+
424462
ValidError(response);
425463

426464
return
@@ -441,7 +479,10 @@ private bool Write(
441479
/// <param name="function">The Modbus function code.</param>
442480
/// <param name="data">The raw data of the request.</param>
443481
/// <returns>The raw data of the response.</returns>
444-
public byte[] Raw(byte deviceId, FunctionCode function, byte[] data)
482+
public byte[] Raw(
483+
byte deviceId,
484+
FunctionCode function,
485+
byte[] data)
445486
{
446487
var request = new Request
447488
{
@@ -451,6 +492,7 @@ public byte[] Raw(byte deviceId, FunctionCode function, byte[] data)
451492
};
452493

453494
var response = SendRequest(request);
495+
454496
ValidError(response);
455497

456498
if (response.IsValid)
@@ -470,6 +512,7 @@ public byte[] Raw(byte deviceId, FunctionCode function, byte[] data)
470512
private Response SendRequest(Request request)
471513
{
472514
var buffer = request.Serialize();
515+
473516
DataWrite(buffer, 0, buffer.Length);
474517

475518
byte id = 0;
@@ -529,16 +572,13 @@ private Response SendRequest(Request request)
529572
expectedBytes += 2;
530573
responseBytes.Add(DataRead(expectedBytes));
531574

532-
#if DEBUG
533-
System.Diagnostics.Debug.WriteLine($"{PortName} RX ({responseBytes.Length}): {Format(responseBytes.Buffer)}");
534-
#endif
575+
Logger?.LogDebug("{0} RX ({1}): {2}", PortName, responseBytes.Length, Format(responseBytes.Buffer));
535576
response = new Response(responseBytes.Buffer);
536-
#if DEBUG
577+
537578
if (response.ErrorCode != ErrorCode.NoError)
538579
{
539-
System.Diagnostics.Debug.WriteLine($"{PortName} RX (E): Modbus ErrorCode {response.ErrorCode}");
580+
Logger?.LogError("{0} RX (E): Modbus ErrorCode {1}", PortName, response.ErrorCode);
540581
}
541-
#endif
542582
}
543583
catch (TimeoutException)
544584
{
@@ -552,11 +592,13 @@ private void ValidParameters(byte deviceId, ushort startAddress)
552592
{
553593
if (deviceId < Consts.MinDeviceId || Consts.MaxDeviceId < deviceId)
554594
{
595+
Logger?.LogError("Invalid Device ID: {0}", deviceId);
555596
throw new ArgumentOutOfRangeException(nameof(deviceId));
556597
}
557598

558599
if (startAddress < Consts.MinAddress || Consts.MaxAddress < startAddress)
559600
{
601+
Logger?.LogError("Invalid start address: {0}", startAddress);
560602
throw new ArgumentOutOfRangeException(nameof(startAddress));
561603
}
562604
}
@@ -565,16 +607,19 @@ private void ValidParameters(byte deviceId, ushort startAddress, ushort count, u
565607
{
566608
if (deviceId < Consts.MinDeviceId || Consts.MaxDeviceId < deviceId)
567609
{
610+
Logger?.LogError("Invalid Device ID: {0}", deviceId);
568611
throw new ArgumentOutOfRangeException(nameof(deviceId));
569612
}
570613

571614
if (startAddress < Consts.MinAddress || Consts.MaxAddress < startAddress + count)
572615
{
616+
Logger?.LogError("Invalid address range: start={0}, count={1}", startAddress, count);
573617
throw new ArgumentOutOfRangeException(nameof(startAddress));
574618
}
575619

576620
if (count < Consts.MinCount || maxReadWrite < count)
577621
{
622+
Logger?.LogError("Invalid count: {0} (max allowed: {1})", count, maxReadWrite);
578623
throw new ArgumentOutOfRangeException(nameof(count));
579624
}
580625
}
@@ -583,6 +628,8 @@ private void ValidError(Response response)
583628
{
584629
if (response.IsValid && response.ErrorCode != ErrorCode.NoError)
585630
{
631+
Logger?.LogError("{0} RX (E): Modbus ErrorCode {1}", PortName, response.ErrorCode);
632+
586633
throw new Exception($"{PortName} RX: Modbus ErrorCode {response.ErrorCode}");
587634
}
588635
}

devices/Modbus/Enums/FunctionCode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ public enum FunctionCode : byte
5757
/// Tunnels service requests and method invocations (Fn 43). 封装接口(MEI).
5858
/// </summary>
5959
EncapsulatedInterface = 0x2B
60-
}
60+
}
6161
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Iot.Device.Modbus
5+
{
6+
/// <summary>
7+
/// Extensions for <see cref="FunctionCode"/>.
8+
/// </summary>
9+
internal static class FunctionCodeExtensions
10+
{
11+
/// <summary>
12+
/// Returns the enum member name for a <see cref="FunctionCode"/> value.
13+
/// </summary>
14+
/// <param name="value">The <see cref="FunctionCode"/> value.</param>
15+
/// <returns>The name of the enum member if defined; otherwise, the numeric value as a string.</returns>
16+
public static string ToNameString(this FunctionCode value)
17+
{
18+
switch (value)
19+
{
20+
case FunctionCode.ReadCoils: return nameof(FunctionCode.ReadCoils);
21+
case FunctionCode.ReadDiscreteInputs: return nameof(FunctionCode.ReadDiscreteInputs);
22+
case FunctionCode.ReadHoldingRegisters: return nameof(FunctionCode.ReadHoldingRegisters);
23+
case FunctionCode.ReadInputRegisters: return nameof(FunctionCode.ReadInputRegisters);
24+
case FunctionCode.WriteSingleCoil: return nameof(FunctionCode.WriteSingleCoil);
25+
case FunctionCode.WriteSingleRegister: return nameof(FunctionCode.WriteSingleRegister);
26+
case FunctionCode.Diagnostics: return nameof(FunctionCode.Diagnostics);
27+
case FunctionCode.WriteMultipleCoils: return nameof(FunctionCode.WriteMultipleCoils);
28+
case FunctionCode.WriteMultipleRegisters: return nameof(FunctionCode.WriteMultipleRegisters);
29+
case FunctionCode.EncapsulatedInterface: return nameof(FunctionCode.EncapsulatedInterface);
30+
default:
31+
// fallback to numeric value
32+
return ((byte)value).ToString();
33+
}
34+
}
35+
}
36+
}

devices/Modbus/Modbus.nfproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<Compile Include="Consts.cs" />
3535
<Compile Include="Enums\FunctionCode.cs" />
3636
<Compile Include="Enums\ErrorCode.cs" />
37+
<Compile Include="Enums\FunctionCodeExtensions.cs" />
3738
<Compile Include="Port.cs" />
3839
<Compile Include="Protocol\Protocol.cs" />
3940
<Compile Include="Server\ModbusServer.cs" />
@@ -57,6 +58,9 @@
5758
<Reference Include="mscorlib, Version=1.17.11.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
5859
<HintPath>packages\nanoFramework.CoreLibrary.1.17.11\lib\mscorlib.dll</HintPath>
5960
</Reference>
61+
<Reference Include="nanoFramework.Logging">
62+
<HintPath>packages\nanoFramework.Logging.1.1.157\lib\nanoFramework.Logging.dll</HintPath>
63+
</Reference>
6064
<Reference Include="nanoFramework.Runtime.Events, Version=1.11.32.0, Culture=neutral, PublicKeyToken=c07d481e9758c731">
6165
<HintPath>packages\nanoFramework.Runtime.Events.1.11.32\lib\nanoFramework.Runtime.Events.dll</HintPath>
6266
</Reference>

devices/Modbus/Modbus.nuspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<dependency id="nanoFramework.System.Collections" version="1.5.67" />
2424
<dependency id="nanoFramework.System.IO.Ports" version="1.1.132" />
2525
<dependency id="nanoFramework.System.Math" version="1.5.116" />
26+
<dependency id="nanoFramework.Logging" version="1.1.157" />
2627
</dependencies>
2728
</metadata>
2829
<files>

devices/Modbus/Modbus.sln

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ EndProject
88
Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "Modbus.Samples", "samples\Modbus.Samples.nfproj", "{6A52BCEF-2C8C-41DD-93E8-F11DA385EC6F}"
99
EndProject
1010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D0AD3A3C-100A-481A-A4FB-284D61EA603D}"
11+
ProjectSection(SolutionItems) = preProject
12+
Modbus.nuspec = Modbus.nuspec
13+
README.md = README.md
14+
version.json = version.json
15+
EndProjectSection
1116
EndProject
1217
Global
1318
GlobalSection(SolutionConfigurationPlatforms) = preSolution

0 commit comments

Comments
 (0)