2using System.Collections;
3using System.Collections.Generic;
4using System.Threading.Tasks;
44 this.MaxCoilNr = 65535;
45 this.MaxDiscreteInputNr = 65535;
46 this.MaxHoldingRegisterNr = 65535;
47 this.MaxInputRegisterNr = 65535;
54 [Page(4,
"Modbus", 100)]
55 [Header(5,
"Unit Address:")]
56 [ToolTip(6,
"Unit ID on the Modbus network.")]
64 [Page(4,
"Modbus", 100)]
65 [Header(30,
"Minimum coil number:")]
66 [ToolTip(31,
"Smallest coil number accepted by the device.")]
74 [Page(4,
"Modbus", 100)]
75 [Header(32,
"Maximum coil number:")]
76 [ToolTip(33,
"Largest coil number accepted by the device.")]
84 [Page(4,
"Modbus", 100)]
85 [Header(34,
"Minimum discrete input number:")]
86 [ToolTip(35,
"Smallest discrete input number accepted by the device.")]
94 [Page(4,
"Modbus", 100)]
95 [Header(36,
"Maximum discrete input number:")]
96 [ToolTip(37,
"Largest discrete input number accepted by the device.")]
104 [Page(4,
"Modbus", 100)]
105 [Header(38,
"Minimum input register number:")]
106 [ToolTip(39,
"Smallest input register number accepted by the device.")]
114 [Page(4,
"Modbus", 100)]
115 [Header(40,
"Maximum input register number:")]
116 [ToolTip(41,
"Largest input register number accepted by the device.")]
118 [DefaultValue(65535)]
124 [Page(4,
"Modbus", 100)]
125 [Header(42,
"Minimum holding register number:")]
126 [ToolTip(43,
"Smallest holding register number accepted by the device.")]
134 [Page(4,
"Modbus", 100)]
135 [Header(44,
"Maximum holding register number:")]
136 [ToolTip(45,
"Largest holding register number accepted by the device.")]
138 [DefaultValue(65535)]
144 [Page(4,
"Modbus", 100)]
145 [Header(46,
"Switch byte order.")]
146 [ToolTip(47,
"If checked, byte order in registers will be reversed.")]
147 [DefaultValue(
false)]
153 [Page(4,
"Modbus", 100)]
154 [Header(60,
"Sensor-Data Read Mode:")]
155 [ToolTip(61,
"How the unit should handle sensor-data requests.")]
157 [Option(
UnitReadMode.ReadRegisters, 62,
"Read and report Modbus registers raw.")]
158 [Option(
UnitReadMode.ReadChildren, 63,
"Read child nodes.")]
179 LinkedList<Parameter> Result = await base.GetDisplayableParametersAsync(
Language, Caller) as LinkedList<Parameter>;
214 throw new Exception(
"Modbus Gateway node not found.");
226 return this.StartReadoutOfRegisters(Request);
229 return this.StartReadoutOfChildren(Request);
233 return Task.CompletedTask;
237 private async Task StartReadoutOfRegisters(
ISensorReadout Request)
241 await Client.
Enter();
244 LinkedList<Field> Fields =
new LinkedList<Field>();
245 DateTime TP = DateTime.UtcNow;
250 while ((StepSize = Math.Min(StepSize,
this.MaxInputRegisterNr - Offset + 1)) > 0 && Offset <=
this.MaxInputRegisterNr)
255 StepSize = Math.Min(StepSize, Values.Length);
257 for (i = 0; i < StepSize; i++)
258 Fields.AddLast(
new Int32Field(
this, TP,
"Input Register 3" + (Offset + i).
ToString(
"D5"),
274 while ((StepSize = Math.Min(StepSize,
this.MaxHoldingRegisterNr - Offset + 1)) > 0 && Offset <=
this.MaxHoldingRegisterNr)
278 ushort[] Values = await Client.
ReadMultipleRegisters((
byte)this.UnitId, (ushort)Offset, (ushort)StepSize);
279 StepSize = Math.Min(StepSize, Values.Length);
281 for (i = 0; i < StepSize; i++)
283 Fields.AddLast(
new Int32Field(
this, TP,
"Holding Register 4" + (Offset + i).
ToString(
"D5"),
284 ModbusUnitHoldingRegisterNode.CheckOrder(
this.SwitchByteOrder, Values[i]),
FieldType.Momentary,
FieldQoS.AutomaticReadout));
300 while ((StepSize = Math.Min(StepSize,
this.MaxCoilNr - Offset + 1)) > 0 && Offset <=
this.MaxCoilNr)
304 BitArray Bits = await Client.
ReadCoils((
byte)this.UnitId, (ushort)Offset, (ushort)StepSize);
305 StepSize = Math.Min(StepSize, Bits.Length);
307 for (i = 0; i < StepSize; i++)
323 while ((StepSize = Math.Min(StepSize,
this.MaxDiscreteInputNr - Offset + 1)) > 0 && Offset <=
this.MaxDiscreteInputNr)
327 BitArray Bits = await Client.
ReadInputDiscretes((
byte)this.UnitId, (ushort)Offset, (ushort)StepSize);
328 StepSize = Math.Min(StepSize, Bits.Length);
330 for (i = 0; i < StepSize; i++)
351 await Client.
Leave();
361 TaskCompletionSource<bool> ReadoutCompleted =
new TaskCompletionSource<bool>();
367 Request.ReportFields(false, e.Fields);
370 ReadoutCompleted.TrySetResult(true);
372 return Task.CompletedTask;
376 if (!(e.Errors is ThingError[] Errors))
378 List<ThingError> List = new List<ThingError>();
380 foreach (ThingError Error in e.Errors)
383 Errors = List.ToArray();
389 ReadoutCompleted.TrySetResult(
true);
391 return Task.CompletedTask;
394 await Sensor.StartReadout(InternalReadout);
396 Task Timeout = Task.Delay(60000);
398 Task T = await Task.WhenAny(ReadoutCompleted.Task, Timeout);
400 if (ReadoutCompleted.Task.IsCompleted)
Base class for Modbus exceptions.
Task Leave()
Leaves unique access to the TCP client. Must be called exactly one for each call to Enter.
async Task< ushort[]> ReadMultipleRegisters(byte UnitAddress, ushort ReferenceNumber, ushort NrWords)
Reads multiple registers from a Modbus unit.
async Task< BitArray > ReadCoils(byte UnitAddress, ushort ReferenceNumber, ushort NrBits)
Reads coils from a Modbus unit.
async Task< ushort[]> ReadInputRegisters(byte UnitAddress, ushort ReferenceNumber, ushort NrWords)
Reads input registers from a Modbus unit.
Task Enter()
Enters unique access to the TCP client. Must be followed by exactly one Leave call.
async Task< BitArray > ReadInputDiscretes(byte UnitAddress, ushort ReferenceNumber, ushort NrBits)
Reads input discretes from a Modbus unit.
Manages a chat sensor data readout request.
Contains information about a language.
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
async Task< INode > GetParent()
Gets the parent of the node.
override string ToString()
Base class for all provisioned metering nodes.
Node representing a TCP/IP connection to a Modbus Gateway
async Task< ModbusTcpClient > GetTcpIpConnection()
Gets the TCP/IP connection associated with this gateway.
Abstract base class for child nodes to Mobus Unit nodes.
Represents a holding register on a Modbus unit node.
Represents a Unit Device on a Modbus network.
ModbusUnitNode()
Represents a Unit Device on a Modbus network.
int MaxDiscreteInputNr
Maximum discrete input number
override Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
int MinDiscreteInputNr
Minimum discrete input number
async Task< ModbusGatewayNode > GetGateway()
Modbus Gateway node.
int MaxCoilNr
Maximum coil number
bool SwitchByteOrder
If the byte order in words should be switched.
override Task< bool > AcceptsParentAsync(INode Parent)
If the node accepts a presumptive parent, i.e. can be added to that parent (if that parent accepts th...
int MinInputRegisterNr
Minimum input register number
Task StartReadout(ISensorReadout Request)
Starts the readout of the sensor.
int UnitId
If the node is provisioned is not. Property is editable.
int MinHoldingRegisterNr
Minimum holding register number
int MaxHoldingRegisterNr
Maximum holding register number
UnitReadMode ReadMode
How the unit should handle sensor-data requests.
override async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
override Task< bool > AcceptsChildAsync(INode Child)
If the node accepts a presumptive child, i.e. can receive as a child (if that child accepts the node ...
int MinCoilNr
Minimum coil number
int MaxInputRegisterNr
Maximum input register number
Tokens available in request.
Represents a boolean value that can be either true or false.
Represents a 32-bit integer value.
Contains information about an error on a thing
Interface for nodes that are published through the concentrator interface.
Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
INode Parent
Parent Node, or null if a root node.
string LogId
If provided, an ID for the node, as it would appear or be used in system logs. Can be null,...
Interface for sensor nodes.
Interface for classes managing sensor data readouts.
string[] FieldNames
Names of fields to read.
Task ReportErrors(bool Done, params ThingError[] Errors)
Report error states to the client.
FieldType Types
Field Types to read.
DateTime To
To what time readout is to be made. Use DateTime.MaxValue to specify no upper limit.
Task ReportFields(bool Done, params Field[] Fields)
Report read fields to the client.
DateTime From
From what time readout is to be made. Use DateTime.MinValue to specify no lower limit.
UnitReadMode
How the unit should handle sensor-data requests
FieldQoS
Field Quality of Service flags
FieldType
Field Type flags