Skip to content

Commit

Permalink
Merge pull request #18 from NikolasK-source/main
Browse files Browse the repository at this point in the history
Release 1.2.3
  • Loading branch information
NikolasK-source authored Sep 2, 2022
2 parents a9ac422 + 666170d commit 5a1d7f6
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 79 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13.4 FATAL_ERROR)
# ======================================================================================================================

# project
project(Modbus_TCP_client_shm LANGUAGES CXX VERSION 1.2.2)
project(Modbus_TCP_client_shm LANGUAGES CXX VERSION 1.2.3)

# settings
set(Target "modbus-tcp-client-shm") # Executable name (without file extension!)
Expand Down
53 changes: 36 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,46 @@ As an alternative to the ```git submodule``` commands, the ```--recursive``` opt

## Use
```
Modbus_TCP_client_shm [OPTION...]
modbus-tcp-client-shm [OPTION...]
-i, --ip arg ip to listen for incoming connections (default: 0.0.0.0)
-p, --port arg port to listen for incoming connections (default: 502)
-n, --name-prefix arg shared memory name prefix (default: modbus_)
--do-registers arg number of digital output registers (default: 65536)
--di-registers arg number of digital input registers (default: 65536)
--ao-registers arg number of analog output registers (default: 65536)
--ai-registers arg number of analog input registers (default: 65536)
-m, --monitor output all incoming and outgoing packets to stdout
-r, --reconnect do not terminate if Master disconnects.
-h, --help print usage
-i, --ip arg ip to listen for incoming connections (default: 0.0.0.0)
-p, --port arg port to listen for incoming connections (default: 502)
-n, --name-prefix arg shared memory name prefix (default: modbus_)
--do-registers arg number of digital output registers (default: 65536)
--di-registers arg number of digital input registers (default: 65536)
--ao-registers arg number of analog output registers (default: 65536)
--ai-registers arg number of analog input registers (default: 65536)
-m, --monitor output all incoming and outgoing packets to stdout
-r, --reconnect do not terminate if the Modbus Server disconnects.
--byte-timeout arg timeout interval in seconds between two consecutive bytes of the same message. In most
cases it is sufficient to set the response timeout. Fractional values are possible.
--response-timeout arg set the timeout interval in seconds used to wait for a response. When a byte timeout is
set, if the elapsed time for the first byte of response is longer than the given timeout,
a timeout is detected. When byte timeout is disabled, the full confirmation response must
be received before expiration of the response timeout. Fractional values are possible.
-t, --tcp-timeout arg tcp timeout in seconds. Set to 0 to use the system defaults (not recommended). (default:
5)
--force Force the use of the shared memory even if it already exists. Do not use this option per
default! It should only be used if the shared memory of an improperly terminated instance
continues to exist as an orphan and is no longer used.
-s, --separate arg Use a separate shared memory for requests with the specified client id. The the client id
(as hex value) is appended to the shared memory prefix (e.g. modbus_fc_DO). You can
specify multiple client ids by separating them with ','. Use --separate-all to generate
separate shared memories for all possible client ids.
--separate-all like --separate, but for all client ids (creates 1028 shared memory files! check/set
'ulimit -n' before using this option.)
-h, --help print usage
--version print version information
--license show licences
The modbus registers are mapped to shared memory objects:
type | name | master-access | shm name
-----|---------------------------|-----------------|----------------
DO | Discrete Output Coils | read-write | <name-prefix>DO
DI | Discrete Input Coils | read-only | <name-prefix>DI
AO | Discrete Output Registers | read-write | <name-prefix>AO
AI | Discrete Input Registers | read-only | <name-prefix>AI
type | name | mb-server-access | shm name
-----|---------------------------|------------------|----------------
DO | Discrete Output Coils | read-write | <name-prefix>DO
DI | Discrete Input Coils | read-only | <name-prefix>DI
AO | Discrete Output Registers | read-write | <name-prefix>AO
AI | Discrete Input Registers | read-only | <name-prefix>AI
```

### Use privileged ports
Expand Down
18 changes: 12 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ One for each register type:
- Discrete Input Registers (AI)

All registers are initialized with 0 at the beginning.
The Modbus master reads and writes directly the values from these shared memories.
The Modbus server reads and writes directly the values from these shared memories.

The actual functionality of the client is realized by applications that read data from or write data to the shared memory.


## Use the Application
The application can be started completely without command line arguments.
In this case the client listens for connections on all IPs on port 502 (the default modbus port).
The application terminates if the master disconnects.
The application terminates if the Modbus server disconnects.

The arguments ```--port``` and ```--ip``` can be used to specify port and ip to listen to.

By using the command line argument ```--monitor``` all incoming and outgoing packets are printed on stdout.
This option should be used carefully, as it generates large amounts of output depending on the masters polling cycle and the number of used registers.
This option should be used carefully, as it generates large amounts of output depending on the Modbus servers polling cycle and the number of used registers.

The ```--reconnect``` option can be used to specify that the application is not terminated when the master disconnects, but waits for a new connection.
The ```--reconnect``` option can be used to specify that the application is not terminated when the Modbus Server disconnects, but waits for a new connection.

The client creates four shared memories and names them ```modbus_DO```, ```modbus_DI```, ```modbus_AO``` and ```modbus_AI``` by default.
The prefix modbus_ can be changed via the argument ```--name-prefix```.
Expand Down Expand Up @@ -76,8 +76,14 @@ This option cannot be used with flatpaks.
setcap 'cap_net_bind_service=+ep' /path/to/binary
```

## Install

## Using the Flatpak package
### Using the Modbus Collection Flapak Package: Shared Memory Modbus (recommended)
[SHM-Modbus](https://nikolask-source.github.io/SHM_Modbus/) is a collection of the shared memory modbus tools.
It is available as flatpak and published on flathub as ```network.koesling.shm-modbs```.


### Using the Standalone Flatpak Package
The flatpak package can be installed via the .flatpak file.
This can be downloaded from the GitHub [projects release page](https://github.com/NikolasK-source/modbus_tcp_client_shm/releases):

Expand All @@ -94,7 +100,7 @@ To enable calling with ```modbus-tcp-client-shm``` [this script](https://gist.gi
In order to be executable everywhere, the path in which the script is placed must be in the ```PATH``` environment variable.


## Build from Source
### Build from Source

The following packages are required for building the application:
- cmake
Expand Down
4 changes: 2 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

target_sources(${Target} PRIVATE main.cpp)
target_sources(${Target} PRIVATE modbus_shm.cpp)
target_sources(${Target} PRIVATE Modbus_TCP_Slave.cpp)
target_sources(${Target} PRIVATE Modbus_TCP_Client.cpp)
target_sources(${Target} PRIVATE license.cpp)


# ---------------------------------------- header files (*.jpp, *.h, ...) ----------------------------------------------
# ======================================================================================================================
target_sources(${Target} PRIVATE modbus_shm.hpp)
target_sources(${Target} PRIVATE Modbus_TCP_Slave.hpp)
target_sources(${Target} PRIVATE Modbus_TCP_Client.hpp)
target_sources(${Target} PRIVATE license.hpp)


Expand Down
26 changes: 13 additions & 13 deletions src/Modbus_TCP_Slave.cpp → src/Modbus_TCP_Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* This program is free software. You can redistribute it and/or modify it under the terms of the MIT License.
*/

#include "Modbus_TCP_Slave.hpp"
#include "Modbus_TCP_Client.hpp"

#include <algorithm>
#include <arpa/inet.h>
Expand All @@ -23,7 +23,7 @@ namespace TCP {

static constexpr int MAX_REGS = 0x10000;

Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t *mapping, std::size_t tcp_timeout) {
Client::Client(const std::string &ip, unsigned short port, modbus_mapping_t *mapping, std::size_t tcp_timeout) {
// create modbus object
modbus = modbus_new_tcp(ip.c_str(), static_cast<int>(port));
if (modbus == nullptr) {
Expand Down Expand Up @@ -62,7 +62,7 @@ Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t *mappi
#endif
}

Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t **mappings, std::size_t tcp_timeout) {
Client::Client(const std::string &ip, unsigned short port, modbus_mapping_t **mappings, std::size_t tcp_timeout) {
// create modbus object
modbus = modbus_new_tcp(ip.c_str(), static_cast<int>(port));
if (modbus == nullptr) {
Expand Down Expand Up @@ -98,7 +98,7 @@ Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t **mapp
#endif
}

void Slave::listen() {
void Client::listen() {
// create tcp socket
socket = modbus_tcp_listen(modbus, 1);
if (socket == -1) {
Expand All @@ -116,7 +116,7 @@ void Slave::listen() {
}

#ifdef OS_LINUX
void Slave::set_tcp_timeout(std::size_t tcp_timeout) {
void Client::set_tcp_timeout(std::size_t tcp_timeout) {
// set user timeout (~= timeout for tcp connection)
unsigned user_timeout = static_cast<unsigned>(tcp_timeout) * 1000;
int tmp = setsockopt(socket, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout, sizeof(tcp_timeout));
Expand Down Expand Up @@ -148,7 +148,7 @@ void Slave::set_tcp_timeout(std::size_t tcp_timeout) {
#endif


Slave::~Slave() {
Client::~Client() {
if (modbus != nullptr) {
modbus_close(modbus);
modbus_free(modbus);
Expand All @@ -157,14 +157,14 @@ Slave::~Slave() {
if (socket != -1) { close(socket); }
}

void Slave::set_debug(bool debug) {
void Client::set_debug(bool debug) {
if (modbus_set_debug(modbus, debug)) {
const std::string error_msg = modbus_strerror(errno);
throw std::runtime_error("failed to enable modbus debugging mode: " + error_msg);
}
}

std::string Slave::connect_client() {
std::string Client::connect_client() {
int tmp = modbus_tcp_accept(modbus, &socket);
if (tmp < 0) {
const std::string error_msg = modbus_strerror(errno);
Expand All @@ -189,7 +189,7 @@ std::string Slave::connect_client() {
return sstr.str();
}

bool Slave::handle_request() {
bool Client::handle_request() {
// receive modbus request
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
int rc = modbus_receive(modbus, query);
Expand Down Expand Up @@ -232,7 +232,7 @@ static inline timeout_t double_to_timeout_t(double timeout) {
return ret;
}

void Slave::set_byte_timeout(double timeout) {
void Client::set_byte_timeout(double timeout) {
const auto T = double_to_timeout_t(timeout);
auto ret = modbus_set_byte_timeout(modbus, T.sec, T.usec);

Expand All @@ -242,7 +242,7 @@ void Slave::set_byte_timeout(double timeout) {
}
}

void Slave::set_response_timeout(double timeout) {
void Client::set_response_timeout(double timeout) {
const auto T = double_to_timeout_t(timeout);
auto ret = modbus_set_response_timeout(modbus, T.sec, T.usec);

Expand All @@ -252,7 +252,7 @@ void Slave::set_response_timeout(double timeout) {
}
}

double Slave::get_byte_timeout() {
double Client::get_byte_timeout() {
timeout_t timeout {};

auto ret = modbus_get_byte_timeout(modbus, &timeout.sec, &timeout.usec);
Expand All @@ -265,7 +265,7 @@ double Slave::get_byte_timeout() {
return static_cast<double>(timeout.sec) + (static_cast<double>(timeout.usec) / (1000.0 * 1000.0));
}

double Slave::get_response_timeout() {
double Client::get_response_timeout() {
timeout_t timeout {};

auto ret = modbus_get_response_timeout(modbus, &timeout.sec, &timeout.usec);
Expand Down
30 changes: 15 additions & 15 deletions src/Modbus_TCP_Slave.hpp → src/Modbus_TCP_Client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace TCP {

constexpr std::size_t MAX_CLIENT_IDS = 256;

//! Modbus TCP slave
class Slave {
//! Modbus TCP client
class Client {
private:
modbus_t *modbus; //!< modbus object (see libmodbus library)
modbus_mapping_t
Expand All @@ -24,36 +24,36 @@ class Slave {
int socket = -1; //!< socket of the modbus connection

public:
/*! \brief create modbus slave (TCP server)
/*! \brief create modbus client (TCP server)
*
* @param ip ip to listen for incoming connections (default 0.0.0.0 (any))
* @param port port to listen for incoming connections (default 502)
* @param mapping modbus mapping object for all client ids
* nullptr: an mapping object with maximum size is generated
* @param tcp_timeout tcp timeout (currently only available on linux systems)
*/
explicit Slave(const std::string &ip = "0.0.0.0",
short unsigned int port = 502,
modbus_mapping_t *mapping = nullptr,
std::size_t tcp_timeout = 5);
explicit Client(const std::string &ip = "0.0.0.0",
short unsigned int port = 502,
modbus_mapping_t *mapping = nullptr,
std::size_t tcp_timeout = 5);

/**
* @brief create modbus slave (TCP server) with dedicated mappings per client id
* @brief create modbus client (TCP server) with dedicated mappings per client id
*
* @param ip ip to listen for incoming connections
* @param port port to listen for incoming connections
* @param mappings modbus mappings (one for each possible id)
* @param tcp_timeout tcp timeout (currently only available on linux systems)
*/
Slave(const std::string &ip,
short unsigned int port,
modbus_mapping_t *mappings[MAX_CLIENT_IDS],
std::size_t tcp_timeout = 5);
Client(const std::string &ip,
short unsigned int port,
modbus_mapping_t *mappings[MAX_CLIENT_IDS],
std::size_t tcp_timeout = 5);

/*! \brief destroy the modbus slave
/*! \brief destroy the modbus client
*
*/
~Slave();
~Client();

/*! \brief enable/disable debugging output
*
Expand All @@ -67,7 +67,7 @@ class Slave {
*/
std::string connect_client();

/*! \brief wait for request from Master and generate reply
/*! \brief wait for request from Modbus Server and generate reply
*
* @return true: connection closed
*/
Expand Down
Loading

0 comments on commit 5a1d7f6

Please sign in to comment.