Skip to content

Enhances Modbus documentation with detailed usage and configuration guidelines#89

Draft
franz-hoepfinger-4diac wants to merge 10 commits intoeclipse-4diac:mainfrom
franz-hoepfinger-4diac:doc
Draft

Enhances Modbus documentation with detailed usage and configuration guidelines#89
franz-hoepfinger-4diac wants to merge 10 commits intoeclipse-4diac:mainfrom
franz-hoepfinger-4diac:doc

Conversation

@franz-hoepfinger-4diac
Copy link
Copy Markdown
Contributor

Updates the Modbus document to improve clarity and detail on configuration,
polling frequency, and data type requirements:

  • Clarifies the mandatory use of Slave ID in certain scenarios.
  • Adds warning about potential CPU load and network flooding when
    pollFrequency is set to 0, and notes about a future single-shot
    reading feature.
  • Describes the caching mechanism and conditions under which Modbus
    read operations update.
  • Includes detailed internal data mapping guidelines for function block
    configuration and describes the importance of matching data types to prevent
    data corruption.
  • Provides concrete examples to guide configuration of common scenarios.

This ensures a comprehensive understanding of the Modbus functionality
and aids in correct implementation.

Clarifies mandatory use cases for Slave ID in Modbus configurations.
Introduces efficiency guidance for polling read addresses.
Updates descriptions for flow control options in Modbus-RTU.

Improves user understanding and configuration accuracy.
Expands the Modbus documentation to include a comprehensive
explanation of function block configurations and data type
mappings. Provides clear examples for various scenarios,
improving user understanding of correct Modbus usage and
embedding practices to avoid communication errors.
Updates documentation on the use of proper IEC data types to
prevent communication errors in Modbus connections. Specifies
mandatory use of exact byte-aligned types and explains potential
issues with using types like BOOL due to compiler-specific
implementations.

Emphasizes accurate mapping between Modbus addresses and
IEC data types for clarity in user configuration. Provides
clarified configuration examples for common scenarios.
Adds explanation of triggering and cyclic behavior for Modbus
function blocks, detailing rules for INIT and REQ events to
ensure stable communication and optimal CPU load usage.

Guides users on using pollFrequency for managing autonomous
transactions and manual triggering requirements.
Clarifies autonomous polling behavior based on frequency value.
Details behavior for reading and writing operations for clarity.
Enhances understanding of Modbus configuration options.

Implements improvements in documentation for better user guidance.
Clarifies the behavior of read operations with caching mechanism
and emphasizes requirement of pollFrequency > 0 for receiving
data. Explains independence of write operations from polling
frequency to optimize performance.

Relates to #doc
Includes cautionary note in documentation clarifying that
setting pollFrequency to zero with readAddresses defined can
cause high CPU load and network congestion. Advises keeping
readAddresses empty to disable reading instead.
Documents upcoming functionality for 'single-shot' read behavior
when pollFrequency is set to 0, improving clarity on expected future
capabilities.
Introduces a code example demonstrating how to write outputs
for an 8-output relay card using Modbus.

Includes an illustrative image to aid understanding.
Copy link
Copy Markdown
Contributor

@azoitl azoitl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this great improvement. I found a few things that I think we should improve. Especially I think we should be more precise with the kind of client FBs and also that there should be some connections. As these are the classical starter problems.

One thing is if we should at right after the setup section that the modbus lib can only be used with client fbs. WDYT?

*** A `REQ` event at the FB does **not** trigger a Modbus read; it only copies the current (cached) data to the outputs.
*** Therefore, to receive any data from the server, you **must** set a frequency > 0.
*** Successful updates from the server will automatically trigger a `CNF` event at the FB.
*** [CAUTION] **WARNING:** Do **not** set `pollFrequency` to `0` if you have `readAddresses` defined. Internally, a frequency of 0 is interpreted as "as fast as possible" (busy waiting). This will result in **100% CPU load** for the Modbus thread and flood your network/bus with requests. If you want to disable reading, leave `readAddresses` empty instead.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asciidoc has the nice Admonition feature for this: https://docs.asciidoctor.org/asciidoc/latest/blocks/admonitions/

I would suggest to change to:

+
[WARNING]
====
Do **not** set `pollFrequency` to `0` if you have `readAddresses` defined. Internally, a frequency of 0 is interpreted as "as fast as possible" (busy waiting).
This will result in **100% CPU load** for the Modbus thread and flood your network/bus with requests. 
If you want to disable reading, leave `readAddresses` empty instead.
====
+
[NOTE]
====
**Future Work:**
We are working on implementing a true "single-shot" read behavior for `pollFrequency = 0`, where a `REQ` event would trigger exactly one Modbus read.
 This documentation will be updated once the feature is available.
====

*** 'd' for discrete input (Read-only bits)
*** 'h' for holding register (Read/Write 16-bit words)
*** 'i' for input register (Read-only 16-bit words)
*** --> see below for a Detailed Table
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*** --> see below for a Detailed Table
+
-> see below for a Detailed Table
+

** **Requirement:** You **must** use 8-bit data types like **`BYTE`**, `SINT`, or `USINT`.
** **Why not `BOOL`?** Internally, `libmodbus` represents each bit as a full `uint8_t` (1 byte). While `BOOL` might work on some systems, the C++ size of `bool` is implementation-defined. If your compiler uses 4 bytes for `bool`, the data pointer will misalign, and communication will fail.
** **Mapping:** 1 Modbus Address = 1 IEC Byte.
** **Example:** Reading `c0..7` (8 bits) requires a `CLIENT_8` FB with 8 pins of type **`BYTE`**. Each byte will contain either `0` or `1`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change this to a CLIENT_0_8 and the pins are always any so I would suggest to write connected to input pins of type BYTE.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes for the Pins,
no for the FB, as written further down, we must mention 3 cases.

** **Multi-Register Types:**
*** **32-Bit Types:** `DWORD`, `DINT`, `REAL` map to **2 consecutive Registers**.
*** **64-Bit Types:** `LWORD`, `LINT`, `LREAL` map to **4 consecutive Registers**.
** **Example:** Reading `h10..11` can be done with a `CLIENT_1` using type `REAL` (combines both registers into one float).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think CLIENT_0_1 is cleaner here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as below. 3 possibilites.

* **INIT (Initialization)**:
** **Rule:** Call `INIT` with `QI=TRUE` **exactly once** at application startup.
** **Avoid cyclic calls:** Do NOT trigger `INIT` repeatedly.
** **Auto-INIT:** If you leave the `INIT` pin of a Modbus client FB unconnected within a SubApplication, 4diac typically handles the initialization automatically (Auto-INIT feature).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove the auto-init feature from here. the auto-init deserves an own page under a planned adavanced features section or?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto init is a General Feature of "EInit" in 4diac.
but i see often Customers connecting INIT to a E_CYCLE.

i totally agree we need a Page therefore.
this one should be linked from here.

#### Scenario C: Reading a Temperature (Float, 32-bit)
* **Hardware:** Sensor maps float value to Registers 10 and 11.
* **String:** `modbus[tcp:192.168.1.20:502::500:h10..11:]`
* **FB:** `CLIENT_1`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLIENT_0_1 and the pin problem

* **FB:** `CLIENT_1`.
* **Configuration:** Set `RD_1` to type `REAL`. The FB automatically reads 2 registers (10 and 11) and combines them into one Float.

#### Scenario D: AkYtec (e.g. AkYtec МК210-301/311) / Bitmasks (Holding Register)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what an AkYtec is. Can we have a generic description of the function in Modbus terms?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://akytec.de/de/mk210-digitales-ein-und-ausgangsmodul.html

Can we have a generic description of the function in Modbus terms?

no. in Modbus Term, this Device is forbidden to exist. Coil is Coil.
but there are Devices out that optimize things, and this Device is one. Many Problems are coming when the user not aware of specialities of Devices ... i need to make another Chapter "Devices" ...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, yes this should be explained more. Maybe in a section special devices

#### Scenario D: AkYtec (e.g. AkYtec МК210-301/311) / Bitmasks (Holding Register)
* **Hardware:** Input states are packed into one 16-Bit Register (Bitmask) at Address 51.
* **String:** `modbus[tcp:192.168.1.99:502::500:h51:]`
* **FB:** `CLIENT_1`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLIENT_0_1 or?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

definitely.

@@ -129,11 +205,10 @@ modbus[rtu:/dev/uart/1:9600:N:8:1::1:2000:c0..7:c0..7]
image:modbus/modbus_8Q.png[modbus with 8Q set]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we update the image to a CLIENT_0_8 to better be aligned with my comments from above? and also have connections on the 8 outputs? as this seems to be the biggest problem for many users.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no.
modbus[rtu:/dev/uart/1:9600:N:8:1::1:2000:c0..7:c0..7]

this is read 8 AND write 8.
it has to be a CLIENT_8. all other would be inconsistent.

we could add another Example with only Writing 8
and another one with only reading 8,
but this String needs a 8/8

and also have connections on the 8 outputs?

definitely.

* **Hardware:** Input states are packed into one 16-Bit Register (Bitmask) at Address 51.
* **String:** `modbus[tcp:192.168.1.99:502::500:h51:]`
* **FB:** `CLIENT_1`.
* **Configuration:** Set `RD_1` to type `WORD`. You will receive an Integer (e.g., 5 means Input 1 and 3 are active). Use `WORD_TO_BOOL` conversion FBs to extract individual bits if needed.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fear I can not follow here. But maybe because of this very special device

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

we must add a picture here right ?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use WORD_TO_BOOL is JUST WRONG! we must use SPLIT_WORD_INTO_BOOLS ...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the picture would definitely help. But I guess also a bit more text.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants