SnapModbus: a new approach to the Modbus commissioning
Due to the chips shortage, today it is increasingly difficult to find Profinet peripherals, so we are increasingly called to use communication technologies that use standard ethernet chips such as Modbus.
Modbus is not a deterministic protocol, but perhaps we don't always need it, and today we need to carefully analyze the technology we use, also in light of the material available on the market.
Furthermore, the use of standard ethernet, in a PC-based system that manages its I/Os at medium-low speeds, saves about €1200 of communication card, or €200 of custom chip for embedded IoT applications.
For this reason, I just released an Open-Source multi-platform suite (library and tools) to manage Modbus communication in strict adherence to the modbus.org specifications, both master and slave side.
You can find it here
It supports all the functions described in the documents:
through the standard transport protocols and the most widespread unofficial protocols: UDP, RTU Over TCP, RTU Over UDP.
It supports the INTEL/ARM (32/64 bit) architecture, works in Windows, Linux, FreeBSD, MacOS and it is Fully thread-safe and embeddable in IoT gateways.
As a member of the Free Software Foundation, I released it under lglp v3: free also for commercial use.
Why SnapModbus?
The Modbus protocol has been consolidated for many years of use, there are millions of devices in the world that implement it and, given that it is a protocol with public and well documented specifications, there are dozens of excellent libraries that implement it, both free and commercial.
So, the question is: did we need any more libraries? How are they different?
The main purpose of this suite is to greatly simplify the commissioning of a Modbus system, Generally, the communication libraries focus only on the way of transferring data to and from the peripheral, limiting themselves to the syntax and showing an "educational" aspect where all the devices are homogeneous.
The reality is quite different, we often find ourselves faced with a "field" made up of various peripherals of different technology (Ethernet or serial) which have different response times and whose data need to be updated with different methods and times. The challenging work is not how to exchange data with one device, but how to exchange data with all of them efficiently.
SnapMB's goal is to manage a complex field as easily and efficiently as possible. This through the abstraction of the transfer protocol (a TCP or RTU client are the same object and its behavior can be changed on the fly) and the availability of two architecture models Half-Duplex Virtual Bus and Fully parallel management.
Virtual Bus?
It’s a protocol-independent half-duplex way to communicate with all devices, regardless of their technology be Ethernet or Serial.
Supposing to have a set of Devices (called Slaves in Modbus, but this term does not should be used anymore) very different from each other, as in figure.
From the hardware point of view, we need to manage three communication channel, one ethernet, the second low-speed serial and the third hi-speed serial (to avoid to degrade the serial communication).
Following the classic approach, we would need to use three different objects, or, at least two objects, one of which has a double instance (the serial one).
Using SnapMB only one object is sufficient: the FieldController, which allows to abstract the technology of the Devices; it is sufficient to create the list of Devices with their indexes and parameters, and then it does the “dirty work” behind the scenes.
in reality, at a low level, more different objects are still needed to manage the Devices, but these are hidden and are managed directly by the FieldController.
Fully parallel management?
It’s a multithreaded way to peer-to-peer data exchange with all devices, including the RTU ones simultaneously.
Referring to the set of Devices above, this time, in addition to having different devices, we also need to manage them with different scan times, because maybe someone acquires slow signals such as energy consumption and someone else manages digital I/O.
Using a half-duplex approach, we would be forced to create an internal clock fast enough to handle the fastest device, and then create “1/n” dividers to handle the slowest devices.
This is quite annoying from a programming point of view. It is also not very efficient because, for example, Ethernet Devices, which can work simultaneously, would be refreshed one by one.
Finally, if our architecture changes, with the addition or removal of some devices, we are forced to restructure the clock and the dividers.
The best way to deal with such a problem is to use a multithreaded architecture.
SnapMB provides the Client object, which allows peer-to-peer communication with its assigned Device, and can do it independently of all the others.
The Client is fully thread-safe and is polymorphic, i.e., it can manage Serial or Ethernet Devices in a completely transparent way.
领英推荐
This will be our conceptual architecture:
Now, while we are used to using TCP clients in multithreaded environments (each client has its own socket), it is strange to think of independent serial clients when the communication channel is unique and cannot be shared.
Again, there is something happening behind the scenes to make our work easier.
The low-level client management mechanism is shown in the next figure.
Each TCP (or UDP) client has its own socket that accesses the network independently from the others. Instead, when we create a serial client, it requests to the ChannelsManager (an internal class) a serial socket with the required characteristics (com port, speed, etc.). The ChannelsManager, if such socket does not exist, creates it, and returns its instance to the client, otherwise it returns the instance of an already created socket.
Each Client, when it must carry out a transaction (send request - wait for response), locks the serial socket, which will put any other clients "on hold" who want to access the Bus. At the end of the transaction the bus will be assigned to another client that was waiting.
This methodology allows us to unify the management of clients by greatly simplifying our code.
Conversely, during destruction, the serial manager manages a reference count for each serial socket.
Finally, if we realize that the serial bus is congested because we have many devices, we can install a second serial adapter and change only and exclusively the identifier of the com port in our clients.
Device
In SnapMB, next to the Clients/Controllers there are the Devices; similarly to the objects already seen, even the Devices are polymorphic, i.e. there is only one Device which can be Ethernet or Serial and work with all the supported transport protocols.
However, due to different technologies, their behavior is different.
The TCP Device (which handles TCP and RTU Over TCP transports) is fully multithreaded and can serve multiple clients simultaneously. It is a full-fledged TCP server that creates a socket associated with a thread for each connection, which independently manages the requests.
The UDP Device (which manages UDP transports and RTU Over UDP) has a single thread but can service and arbitrate the requests of multiple UDP clients.
Both TCP and UDP Devices have a PeerList, which can be AllowList or BlockList (synonyms for terms that should no longer be used: blacklist and whitelist), in which it is possible to store the IP addresses that can access or those whose consent is denied.
Finally, the Serial Device (which handles RTU and ASCII formats) has a single thread and handles requests from a single Client or Controller, since there is no concept of master address on the serial line.
User program Interface
The Device is a “request handler” i.e., an object that replies to the Client/Controller request. All this cannot happen in a completely autonomous way, it is necessary that our application is aware of this data exchange and that it can modify its behavior accordingly.
The Device, once created, communicates with our application through shared resources and/or callbacks.
Shared resources
This is the most intuitive method, we allocate four memory areas in our application (struct or Array) and tell the Device: these are your Holding registers, Coils, Input registers and Discrete inputs; when the Controller requests to read or write something, you must use these areas.
Concurrency
The memory areas exist in our application, so we can access them at any time, however, since we do not know when the Device reads or writes to them, it is necessary to synchronize access to avoid reading "partial data".
To do this, the Device provides Lock/Unlock and Safe Copy Area methods that allow you to lock the memory area before accessing it.
Concurrent access of multiple socket threads is also governed by a critical section, and this happens automatically.
Finally, if we need to know when a device has written/read data in a certain area, we can use the Event Callback.
Callbacks
Callbacks are functions (implemented as Delegates in C#) in our code which are called by the Device when something happens. And usually, they are associated to a Modbus functions.
In other words, we can say to the Device: when you receive a request “0x08: Diagnostics” you must call this function
Callbacks too are thread safe.
Hope it helps..
Un Genio! Volevo farti i miei piu' sinceri complimenti! Inizio adesso ad usare la tua libreria,per fare dei test di funzionamento. Spero che se ho qualche problema posso farti delle domande. Grazie ancora di tutto!
Automation Engineer
2 年Davide sei un "grande". Hai donato al mondo Snap7 utilizzato da una moltitudine di tecnici a livello internazionale ed ora consegni alla comunità un'altra grande opera di ingegno e talento per uno dei fieldbus di maggiore utilizzo in ambito industriale [ModBus]. Grazie.