Code Monkey home page Code Monkey logo

libmodbus's Introduction

A groovy modbus library

Build Status

Overview

libmodbus is a free software library to send/receive data with a device which respects the Modbus protocol. This library can use a serial port or an Ethernet connection.

The functions included in the library have been derived from the Modicon Modbus Protocol Reference Guide which can be obtained from www.modbus.org.

The license of libmodbus is LGPL v2.1 or later.

The official website is www.libmodbus.org. The website contains the latest version of the documentation.

The library is written in C and designed to run on Linux, Mac OS X, FreeBSD, Embox, QNX and Windows.

You can use the library on MCUs with Embox RTOS.

Installation

You will only need to install automake, autoconf, libtool and a C compiler (gcc or clang) to compile the library and asciidoc and xmlto to generate the documentation (optional).

To install, just run the usual dance, ./configure && make install. Run ./autogen.sh first to generate the configure script if required.

You can change installation directory with prefix option, eg. ./configure --prefix=/usr/local/. You have to check that the installation library path is properly set up on your system (/etc/ld.so.conf.d) and library cache is up to date (run ldconfig as root if required).

The library provides a libmodbus.pc file to use with pkg-config to ease your program compilation and linking.

If you want to compile with Microsoft Visual Studio, you should follow the instructions in ./src/win32/README.md.

To compile under Windows, install MinGW and MSYS then select the common packages (gcc, automake, libtool, etc). The directory ./src/win32/ contains a Visual C project.

To compile under OS X with homebrew, you will need to install the following dependencies first: brew install autoconf automake libtool.

To build under Embox, you have to use its build system.

Testing

Some tests are provided in tests directory, you can freely edit the source code to fit your needs (it's Free Software :).

See tests/README for a description of each program.

For a quick test of libmodbus, you can run the following programs in two shells:

  1. ./unit-test-server
  2. ./unit-test-client

By default, all TCP unit tests will be executed (see --help for options).

It's also possible to run the unit tests with make check.

To report a bug or to contribute

See CONTRIBUTING document.

Documentation

You can serve the local documentation with:

pip install mkdocs-material
mkdocs serve

libmodbus's People

Contributors

andreysv avatar bachp avatar cedricboudinet avatar desowin avatar jetforme avatar jlnr avatar karlp avatar kwarf avatar lanurmi avatar matthijsk avatar mhei avatar mk8 avatar ndim avatar ndunks avatar octo avatar oldfaber avatar pboettch avatar prodrive-ci avatar public avatar rgenoud avatar staldert avatar stefannilsson avatar stephane avatar szlin avatar thecount avatar timgates42 avatar tobydox avatar v-zhuravlev avatar vuokko avatar yegorich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libmodbus's Issues

assertion failure in "modbus-rtu.c"

When I compile and run the following code:

include

include "modbus.h"

include "modbus-rtu.h"

include <errno.h>

include

using namespace std;
int main(){
modbus_t *ctx;
uint16_t tab_reg[64];
int rc;
int i;
ctx = modbus_new_rtu("/dev/ttyS3", 115200, 'N', 8, 1);
if (ctx == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
return -1;
}
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
rc = modbus_read_registers(ctx, 0, 10, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
for (i=0; i < rc; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}

In I get the following error:

assertion "ctx->slave != -1" failed: file "modbus-rtu.c", line 119, function: _modbus_rtu_build_request_basis
Aborted (core dumped)

In the Windows Command Prompt (compiled under MinGW) its:

Assertion failed: ctx->slave != -1, file modbus-rtu.c, line 119

This Application has requested the Runtime to terminate it in an unusual way.

What am I doing wrong?

Long connect timeout if TCP device is down.

If a Modbus TCP device or a Modbus TCP gateway is down, the timeout is too long. With down, i mean that the device could be off, broken, inaccesible due to a network problem... I compiled the library on Windows with MinGW and CodeBlocks. I've an Ubuntu development environment too, and the problem is the same.

I modified the code to include a timeout for the connection function, as it exists in the response function. It's working in my Modbus TCP network now without any known problem.

I am not used to github so i don't know how to contribute the modified code to be evaluated.
Could someone help me to contribute the changes?

modbus_rtu_set_serial_mode ERROR

First of all, sorry for my English.

I always get an error when try to use that function. What can I do? Every call I do (modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485 (or RS232)) returns -1. Bad file descriptor.

I've followed the examples but I cannot go throught that issue.

Anyone could help me?

int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode)
{
if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {

if HAVE_DECL_TIOCSRS485

    modbus_rtu_t *ctx_rtu = ctx->backend_data;
    struct serial_rs485 rs485conf;
    memset(&rs485conf, 0x0, sizeof(struct serial_rs485));

    if (mode == MODBUS_RTU_RS485) {
        rs485conf.flags = SER_RS485_ENABLED;
        if (ioctl(ctx->s, TIOCSRS485, &rs485conf) < 0) {

            // ALWAYS FAILS HERE <<<-----------------------------------------------------------------------------------------------------------------

            return -1;
        }

        ctx_rtu->serial_mode |= MODBUS_RTU_RS485;
        return 0;
    } else if (mode == MODBUS_RTU_RS232) {
        if (ioctl(ctx->s, TIOCSRS485, &rs485conf) < 0) {
            return -1;
        }

        ctx_rtu->serial_mode = MODBUS_RTU_RS232;
        return 0;
    }

else

    if (ctx->debug) {
        fprintf(stderr, "This function isn't supported on your platform\n");
    }
    errno = ENOTSUP;
    return -1;

endif

}

/* Wrong backend and invalid mode specified */
errno = EINVAL;
return -1;

}

server: static implementation of mappings - memory inefficiency

Hi,

I'm evaluating a modbus stack for a new application (TCP server).

If I read the code correctly, if I'm writing a modbus server and need to support reading from registers with address up to N, I must allocate an uint16_t[0..N] array.
This might be very inefficient, if the register address space is sparse, i.e. only a few registers are used, but some of them have high addresses. In the worst case, I might need to allocate 2^16 * 2byte = 128MB only for reading registers.
Is this correct?

To make it worse, it looks like many implementation artificially divide the 16 bit address range into subranges dedicated to input/output coils/registers (http://www.control.com/thread/1026238596), so a large part of those arrays would be always wasted.

is there any plan to improve the mapping implementation to better address sparse register address spaces, for example with an hashtable, or by specifying starting offset for the arrays (i.e., modbus_mapping_new would accept 4 new parameters do define the base for each data type)?

Thank you and Best Regards

MAtteo Valsasna

modbus_report_slave_id doesn't understand exception responses

When the response comes in, it somehow ends up in the regular checks in check_confirmation, instead of the path for exception replies. This results in a message in the debug about an unexpected function, when it should be properly decoding teh exception like, "function not supported"

(Testing with a device that doesn't support the slave id function)

Enhancement Request: modbus over UDP/IP

I wonder if there are any plans to have libmodbus support UDP in addition to TCP. I've implemented modbus routines in Erlang a while ago and realized that modbus communication usually consist of just a request packet followed up by a reply packet. Establishing and tearing down a virtual channel for this seems excessive (unless your PLC requires it, of course).

tcp_new requires a node address, _listen method doesn't want it

In modbus_new_tcp_pi(), (I haven't looked at the regular version), the following code is used to set up the hostname of the remote server: https://github.com/stephane/libmodbus/blob/master/src/modbus-tcp.c#L701

ret_size = strlcpy(ctx_tcp_pi->node, node, dest_size);

Then in modbus_tcp_pi_listen there is a check no the node element being 0, which then properly sets up the socket to listen on NULL, for any address. https://github.com/stephane/libmodbus/blob/master/src/modbus-tcp.c#L435

However, given the way the check is done in new(), there's no way to set the node to a zero value. I suggest that if the incoming node is NULL, that it be set to zero,

modbus_set_slave() disallows Slave IDs above 247

modbus_set_slave() disallows Slave IDs above 247. A particular modbus device that I am using defaults to a slave ID above 247 (specifically, 254) and does broadcast on IDs 255 and 0. This means that I cannot interact with this device directly.

There are workarounds involving taking the device onto it's own bus not shared with other devices and then using the broadcast address to set the device ID to a normal value. However, this is not ideal for my situation.

in modbus-tcp.c and modbus-rtu.c exists the following line:

    if (slave >= 0 && slave <= 247) {

I recompiled the library with these lines changed to:

    if (slave >= 0 && slave <= 255) {

and this fixed my issue.

I believe this restriction is in place in order to adhere to modbus standards, however, with the large number of non-compliant devices out there, I believe libmodbus should give this power to the developer. Another possibility is printing a warning message if this is performed while the library is in debug mode when using addresses from that range.

send with ERROR_RECOVERY_LINK has no escape hatch

Calling send will block forever if the link cannot be reestablished.

I have many cases where closing and reopening is the right thing to do, and normally works very well, but blocking forever is not OK. Could the modbus_get_response_timeout time be used to limit this? or some other mechanism? Or are there any other ways to work around this?

the receive code only closes and reconnects once, so I don't understand why the send code should be trying forever

_modbus_rtu_check_integrity seems to fail?

I'm having some issues with libmodbus, that as best I can tell, are problems coming from the rtu CRC check.

If I simply ignore the return codes, everything works just fine. in debug mode, I see the expected bytes and all the devices respond appropriately. However, the return code is always -1, and errno is always set to 9 Bad file descriptor.

Opening /dev/ttyUSB000 at 115200 bauds (N, 8, 1)
[01][06][00][01][00][FA][58][49]
Waiting for a confirmation...
<01><06><00><01><00><58><49>
write failed: 9 Bad file descriptor
[01][06][00][00][00][37][C8][1C]
Waiting for a confirmation...
<01><06><00><00><00><37><1C>
write failed: 9 Bad file descriptor

It all works though, which is annoying. I have the same behaviour with an AVR modbus slave, and also with a second libmodbus fake slave, connected via socat PTY,link=COM8 PTY,link=COM9

Using the calculators at http://www.lammertbies.nl/comm/info/crc-calculation.html I can manually enter the modbus frame, and see that for...<01><06><00><01><00><58><49>, the crc16 (modbus) is 0x4958. Which I guess is ok, and matches <58><49> ?

Any idea what I'm likely to be missing?
libmodbus5 version 3.0.1-2 (debian squeeze/stable)

sample code is at https://gist.github.com/1201476

Compilation problem on Windows/MinGW/GCC

Hello

I found a little compile problem on windows with MinGW and GCC. The line
GetLastError()); in modbus-tcp.c:67 has to be turned to (unsigned int)GetLastError());

Then it compiles. I think it is a hack because we are using the GetLastError() windows API while the fprintf is the GNU version from MinGW. That's not really critic since this it is just a fprintf message.

acinclude.m4 tests for wrong file

if you download a release the man file doesn't get installed because of the following issue:
in acinclude.m4 in line 23 it tests for doc/modbus.7 but it should rather check for doc/libmodbus.7 otherwise it assumes it isn't a release version.

Wrong return value of _modbus_tcp_pi_connect() on failure

If getaddrinfo() fails inside _modbus_tcp_pi_connect() "rc" is returned at line 305.
This is not consistent with _modbus_tcp_connect that always return -1, and with the
documentation of modbus_connect().
"return rc" should be "return (-1)".

Moreover errno is not set, but this is a bigger issue, as errno is not set for
many errors.

Regards

Fabio

device field in modbus_param_t is too small

as already predicted in the comment modbus.h, the restriction of having only 16 bytes for the device name becomes a problem when using udev-created symlinks on Linux, as they tend to be way longer than 16 bytes.
a) Maybe it could always be 64 bytes, independently of the OS used?
b) Maybe it could even be a pointer to a string, thus allowing an arbitrary length of the device-name?
I'd vote for a), as it actually reduces complexity and most probably solves the problem for now.

Version wrong?

Hi Stephane,

Just a minor bug I think: On the website (libmodbus.org) you report the latest development/unstable version to be 2.9.1, however the configure generates a modbus-version.h file containing version 2.1.1

Need more tests…

There's currently no tests covering data corruption, timeouts etc.

There should be some. I intend to write some at some point in the near future but if someone get's there before me I'll help out.

errors during 'make' in MinGW

Tried this several times.
I never have an autogen.sh or a configure.sh file so I skip that step.
I run ./configure and it seems to work, at least it does things.
When I run "make" it spits out a bunch of errors like:

modbus-rtu.c: In function '_modbus_rtu_connect':
modbus-rtu.c:355:9 error: expected ';' before 'ctx_rtu'
modbus-rtu.c:455:9 error: expected ';' before 'ctx_rtu'
make[1]: *** {modbus-rtu.lo] Error 1"
...

The same with "make install"
The end result is I have no usable library files in the .lib folder, just a modbus.o and a modbus-data.o

I only have this problem in MingW. I tried it in Cygwin a few times and everything seems to work fine there.
Is there a log file excerpt I can post so someone can show me what I'm doing wrong?

Error using modbus_tcp_pi

_modbus_tcp_pi_connect() fails under Windows with error 10093 WSANOTINITIALISED.
It should call to _modbus_tcp_init_win32() like _modbus_tcp_connect(). This patch fixes this.
I checked github and I think this is still an error in master.

Regards
Fabio

--- libmodbus-3.0.2/src/modbus-tcp.c 2012-01-25 05:29:36.000000000 +0100
+++ libmodbus-3.0.2-new/src/modbus-tcp.c 2012-05-18 14:08:46.767905000 +0200
@@ -288,6 +288,12 @@ static int _modbus_tcp_pi_connect(modbus
struct addrinfo ai_hints;
modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data;

+#ifdef OS_WIN32

  • if (_modbus_tcp_init_win32() == -1) {
  •    return -1;
    
  • }
    +#endif

memset(&ai_hints, 0, sizeof(ai_hints));
#ifdef AI_ADDRCONFIG
ai_hints.ai_flags |= AI_ADDRCONFIG;

Patch for hardware that echoes transmitted bytes

Hello there.

First I want to thank Stephane for this work. Kudos man! This is a great library that makes working with Modbus so easy ! and I can get it on my Debian machines by only using apt-get! Thanks a lot! I know is not easy to find the time and energy to organize and share your work.

Now to the subject: I'm using libmodbus on a Technologic Systems TS-7800 SBC with the RS485 optional bus. It turns out that this board's MAX485 is wired in such a way that the receiver is always enabled (check out page 6 of it's schematic bottom-right corner) so everything you transmit gets back on the receive buffer, libmodbus thinks it is the slave answer and fails with a checksum error.

I tried to fix it by disabling the receiver before transmitting with tcsetatrr and turning it back on after transmission but it didn't worked, the bytes were still echoed to the receive buffer. So finally I fixed it by reading from the port the same amount of bytes transmitted so they get out of the buffer.

I think this can be useful to someone else who has hardware that echoes the transmitted bytes. So I add a new field to the modbus_rtu structure and, added a couple functions and modified the rtu's transmit function. The new functions are:

int modbus_rtu_set_echohw_mode(modbus_t *ctx, uint8_t mode);
int modbus_rtu_get_echohw_mode(modbus_t *ctx);

echohw mode can be one of MODBUS_RTU_NO_ECHOHW and MODBUS_RTU_HAS_ECHOHW. By default the RTU is in MODBUS_RTU_NO_ECHOHW which means it works as usual, but if you change it to MODBUS_RTU_HAS_ECHOHW then all the transmitted bytes will be taken out of the receive buffer.

Please excuse me for sending the patch this way but I'm not familiar with how patches should be send on Github. Maybe I should fork or something but I'm on a hurry and I want to share this before I forget. So after this paragraph comes the patch against the src directory of the current stable version (3..0.1). And once again, thanks for the great work.

diff -rupN src-orig/modbus-rtu.c src/modbus-rtu.c
--- src-orig/modbus-rtu.c   2011-10-23 12:29:38.000000000 -0500
+++ src/modbus-rtu.c    2011-10-23 13:56:33.000000000 -0500
@@ -264,7 +264,28 @@ ssize_t _modbus_rtu_send(modbus_t *ctx,
DWORD n_bytes = 0;
return (WriteFile(ctx_rtu->w_ser.fd, req, req_length, &n_bytes, NULL)) ? n_bytes : -1;
#else
-    return write(ctx->s, req, req_length);
+    int w, r, i;
+    uint8_t *rb;
+    modbus_rtu_t *ctx_rtu = ctx->backend_data;
+    
+    // Transmit
+    w= write(ctx->s, req, req_length);
+    
+    // Read back written bytes if hw has echo
+    if (ctx_rtu->echohw) {
+      rb = malloc(w);
+      r= 0;
+      while (r < w)
+        r += read(ctx->s, rb + r, w - r);
+      if (ctx->debug) {
+        for (i = 0; i < r; ++i)
+          fprintf(stderr, "|%02X|", rb[i]);
+        fprintf(stderr, "\n");
+      }
+      free(rb);
+    }
+    
+    return w;
#endif
}

@@ -764,6 +785,29 @@ int modbus_rtu_get_serial_mode(modbus_t
}
}

+int modbus_rtu_set_echohw_mode(modbus_t* ctx, uint8_t mode) {
+  if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
+    modbus_rtu_t* rtu = (modbus_rtu_t*) ctx->backend_data;
+    rtu->echohw= mode;
+    return 0;
+  }
+  /* Wrong backend and invalid mode specified */
+  errno = EINVAL;
+  return -1;
+
+}
+
+int modbus_rtu_get_echohw_mode(modbus_t* ctx) {
+  if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
+    modbus_rtu_t* rtu = (modbus_rtu_t*) ctx->backend_data;
+    return rtu->echohw;
+  }
+  /* Wrong backend and invalid mode specified */
+  errno = EINVAL;
+  return -1;
+
+}
+
void _modbus_rtu_close(modbus_t *ctx)
{
/* Closes the file descriptor in RTU mode */
@@ -912,6 +956,11 @@ modbus_t* modbus_new_rtu(const char *dev
}
ctx_rtu->data_bit = data_bit;
ctx_rtu->stop_bit = stop_bit;
+    
+#if HAVE_DECL_TIOCSRS485    
+    ctx_rtu->serial_mode = MODBUS_RTU_RS232;
+#endif    
+    ctx_rtu->echohw= MODBUS_RTU_NO_ECHOHW;

return ctx;
}
diff -rupN src-orig/modbus-rtu.h src/modbus-rtu.h
--- src-orig/modbus-rtu.h   2011-10-23 12:29:38.000000000 -0500
+++ src/modbus-rtu.h    2011-10-22 17:47:14.000000000 -0500
@@ -35,4 +35,10 @@ modbus_t* modbus_new_rtu(const char *dev
int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
int modbus_rtu_get_serial_mode(modbus_t *ctx);

+#define MODBUS_RTU_HAS_ECHOHW 1
+#define MODBUS_RTU_NO_ECHOHW 0
+
+int modbus_rtu_set_echohw_mode(modbus_t *ctx, uint8_t mode);
+int modbus_rtu_get_echohw_mode(modbus_t *ctx);
+
#endif /* _MODBUS_RTU_H_ */
diff -rupN src-orig/modbus-rtu-private.h src/modbus-rtu-private.h
--- src-orig/modbus-rtu-private.h   2011-10-23 12:29:38.000000000 -0500
+++ src/modbus-rtu-private.h    2011-10-22 17:47:14.000000000 -0500
@@ -81,6 +81,7 @@ typedef struct _modbus_rtu {
#if HAVE_DECL_TIOCSRS485
int serial_mode;
#endif
+    uint8_t echohw;
} modbus_rtu_t;

#endif /* _MODBUS_RTU_PRIVATE_H_ */

modbus_set_float() and modbus_get_float() reversed register order

The modbus_set_float() and modbus_get_float() calls appear to be use a reversed register order from what is documented in the MODBUS specification. e.g. The float number 2.0 has a hexadecimal representation of 0x4000000 but the modbus_set_float() call copies 0x0000 in the first register and 0x4000 into the second register. Unless I am mistaken this is not the big-endian order specified in the specification.

Fix Windows compilation in master

Windows connect() does not set errno, and EINPRORGESS is not defined.

The patch below fixes it.
(Is it possible to attach a file with the patch ?)

I also have many more patches.
Should I create a fork ?
I would really like to upstream the acceptable ones.

The first would be the creation of a win32 directory with a self-contained
Visual Studio Express 2008 project file to create a modbus.dll.
To create a useful DLL I need to mark the exported functions with
...
EXPORT void modbus_close(modbus_t *ctx);
...
in the headers and sources.
Obviously EXPORT is only defined under _WIN32.
Is this acceptable ?

Regards
Fabio

+++ PATCH

--- stephane-libmodbus-2dca042/src/modbus-tcp.c 2012-05-28 17:00:22.000000000 +0200
+++ p1-libmodbus/src/modbus-tcp.c 2012-06-06 15:45:20.457647000 +0200
@@ -243,7 +243,11 @@ static int _connect(int sockfd, const st
int rc;

 rc = connect(sockfd, addr, addrlen);

+#if defined(_WIN32)

  • if (rc == -1 && WSAGetLastError() == WSAEINPROGRESS) {
    +#else
    if (rc == -1 && errno == EINPROGRESS) {
    +#endif
    fd_set wset;
    int optval;
    socklen_t optlen = sizeof(optval);

[PATCH] fix compilation

A semicolon is missing. Please apply.

Best regards.

oldfaber

--- libmodbus-3.0.2\src\modbus-rtu.c 2012-01-25 05:29:36.000000000 +0100
+++ libmodbus-3.0.2-new\src\modbus-rtu.c 2012-04-17 15:22:20.640656500 +0200
@@ -351,7 +351,7 @@
if (!GetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb)) {
fprintf(stderr, "ERROR Error getting configuration (LastError %d)\n",
(int)GetLastError());

  •    CloseHandle(ctx_rtu->w_ser.fd)
    
  •    CloseHandle(ctx_rtu->w_ser.fd);
     ctx_rtu->w_ser.fd = INVALID_HANDLE_VALUE;
     return -1;
    
    }
    @@ -455,7 +455,7 @@
    if (!SetCommState(ctx_rtu->w_ser.fd, &dcb)) {
    fprintf(stderr, "ERROR Error setting new configuration (LastError %d)\n",
    (int)GetLastError());
  •    CloseHandle(ctx_rtu->w_ser.fd)
    
  •    CloseHandle(ctx_rtu->w_ser.fd);
     ctx_rtu->w_ser.fd = INVALID_HANDLE_VALUE;
     return -1;
    
    }

Small compilation bug in 3.0.2 under windows

in modbus-rtu.c missed ";" after CloseHandle(ctx_rtu->w_ser.fd) two times in line 458 and 354

if (!GetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb)) {
fprintf(stderr, "ERROR Error getting configuration (LastError %d)\n",
(int)GetLastError());
CloseHandle(ctx_rtu->w_ser.fd)
ctx_rtu->w_ser.fd = INVALID_HANDLE_VALUE;
return -1;
}

Need to clone modbus_t TCP context

In order to create a multi-threaded TCP server, it is necessary to duplicate the modbus_t TCP context, but no function currently exists to do this. Additionally, the modbus_t structure points to connection-specific data, so a simple memcpy() doesn't do the job.

Below is a patch which provides the appropriate functions.

diff -r a/libmodbus/src/modbus-tcp.c b/libmodbus/src/modbus-tcp.c
--- a/libmodbus/src/modbus-tcp.c
+++ b/libmodbus/src/modbus-tcp.c
@@ -732,3 +732,19 @@

 return ctx;

}
+
+void modbus_clone_tcp(modbus_t* new_ctx, modbus_t* ctx)
+{

  • new_ctx = (modbus_t *) malloc(sizeof(modbus_t));
  • memcpy(new_ctx, ctx, sizeof(modbus_t));
  • new_ctx->backend_data = (modbus_tcp_t *) malloc(sizeof(modbus_tcp_t));
  • memcpy(new_ctx->backend_data, ctx->backend_data, sizeof(modbus_tcp_t));
    +}

+void modbus_clone_tcp_pi(modbus_t* new_ctx, modbus_t* ctx)
+{

  • new_ctx = (modbus_t *) malloc(sizeof(modbus_t));
  • memcpy(new_ctx, ctx, sizeof(modbus_t));
  • new_ctx->backend_data = (modbus_tcp_pi_t *) malloc(sizeof(modbus_tcp_pi_t));
  • memcpy(new_ctx->backend_data, ctx->backend_data, sizeof(modbus_tcp_pi_t));
    +}
    diff -r a/libmodbus/src/modbus-tcp.h b/libmodbus/src/modbus-tcp.h
    --- a/libmodbus/src/modbus-tcp.h
    +++ b/libmodbus/src/modbus-tcp.h
    @@ -41,9 +41,11 @@
    modbus_t* modbus_new_tcp(const char *ip_address, int port);
    int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
    int modbus_tcp_accept(modbus_t *ctx, int *socket);
    +void modbus_clone_tcp(modbus_t *new_ctx, modbus_t *ctx);

modbus_t* modbus_new_tcp_pi(const char *node, const char *service);
int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection);
int modbus_tcp_pi_accept(modbus_t *ctx, int *socket);
+void modbus_clone_tcp_pi(modbus_t *new_ctx, modbus_t *ctx);

endif /* MODBUS_TCP_H */

runtime error "Assertion failed" in modbus-rtu.c

When I run this:

include

include "modbus.h"

include "modbus-rtu.h"

include <errno.h>

include

using namespace std;

int main()
{
modbus_t *ctx;
uint16_t tab_reg[64];
int rc;
int i;
ctx = modbus_new_rtu("/dev/ttyS3", 115200, 'N', 8, 1);
if (ctx == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
return -1;
}
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
rc = modbus_read_registers(ctx, 0, 10, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
for (i=0; i < rc; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}

I get this:

assertion "ctx->slave != -1" failed: file "modbus-rtu.c", line 119, function: _modbus_rtu_build_request_basis
Aborted (core dumped)

I am using libmodbus-3.0.2 with Cygwin. How should I proceed in order to fix this problem?

I understand that libmodbus was written to be compiled under MinGW and NOT Cygwin but as I mentioned before I can not seem to generate the libmodbus libraries in my MinGW shell but I CAN under Cygwin.

server behind a firewall

hi
I'm experiencing the following problem: I have a client and server separate by a firewall.
My client test program does two consecutive call using TCP connection to the server on port 8001. This port is internally forwarded to port 502 of modbus server.
The first call goes fine, the second one crashs (core dump) the client when tries to use the modbus context the second time.
here follows the code:

for i=0 to 2 {
mb = modbus_new_tcp( "80.116.197.158", PORT);
modbus_connect(mb);
/* Read registers */
if (modbus_read_registers(mb, addr, nregs, tab_reg) == -1) {
logvalue(logname,"Errore reading from modbus server\n");
}
}

Platform are:
client openbsd 4.7
server: freebsd
firewall: freebsd pf firewall

The same behaviour is when I complile modbus library on windows using the same client/server test code.

help very appreciated.

Vittorio

Enhancement Request: ability to redirect traces to any file, debug feature

It would be a nice debug facility to have ability to dump traces to any file instead of stdout and stderr as of today. This could be a setting, active when setting debug active with modbus_set_debug().
I'm ready to propose API and code the feature. (In fact I've already done it for other software).
Sorry if this is not the place for ER's (Enhancement Request), I could not find one. If so, help me by redirecting the request.
Thanks

Visual Studio

Does anyone have a visual studio project for this library?
I'm missing some include files and I can't find them.

doc fixes

diff --git a/doc/modbus_get_header_length.txt b/doc/modbus_get_header_length.txt
index fb23cdb..77232f0 100644
--- a/doc/modbus_get_header_length.txt
+++ b/doc/modbus_get_header_length.txt
@@ -15,7 +15,7 @@ SYNOPSIS
DESCRIPTION


The modbus_get_header_length() function shall retrieve the current header
-length from the backend. This fonction is convenient to manipulate a message and
+length from the backend. This function is convenient to manipulate a message and
so its limited to low-level operations.

diff --git a/doc/modbus_read_input_bits.txt b/doc/modbus_read_input_bits.txt
index ab6ba2d..5d54078 100644
--- a/doc/modbus_read_input_bits.txt
+++ b/doc/modbus_read_input_bits.txt
@@ -21,7 +21,7 @@ in 'dest' array as unsigned bytes (8 bits) set to TRUE or FALSE.
You must take care to allocate enough memory to store the results in 'dest'
(at least 'nb' * sizeof(uint8_t)).

-The function uses the Modbus function code 0x03 (read input status).
+The function uses the Modbus function code 0x02 (read input status).

RETURN VALUE

Oops....

Sorry about the multiple posts. I'll delete them as soon as I figure out how.

Allow custom _modbus_rtu_ioctl_rts function

The _modbus_rtu_ioctl_rts function is called when you are in rs485 mode, and does all the good things based on the config of the port and the wait times. However, it is hardcoded to send some fixed ioctls(), On my platform at least, I don't have a real RTS signal on the serial port to use, but I can emulate it with a GPIO.

I've got this working by hacking my own method into that file, but it's pretty ugly.

It might be nice if this could be specified as a function pointer to register to do this, rather than being hardcoded to send ioctl(fd, TIOCMSET, &flags);

multiple slaves with RTU communication

Hi!

I've got a problem with RTU communication.
On an RTU link (RS485) I've got one master and two slaves.

The problem is, that when a master starts a "modbus_read_input_registers" communication. The starting message arrives for both of the slave. The one, which is addressed acknowledges the message, creates the reply and sends it back. The other one, with different salve id, receives the first message, it sees that he is not the one who is addressed, so does nothing.

But when it receives the reply of the first slave, it reports an error, because of the wrong CRC. The problem is that, the reply is a longer message, and the second slave doesent see that, and checks the CRC from false part of the reply message.

How should I handle this situation?

Thanks in advance,
Tamas

Add functions for reading raw data

I would like a function to be able to get the raw data back from a sending request or a response. I have some code that copies msg in send_msg() and receive_msg(), but I'm having some memory leaks, so I'd like to know how to move forward.

Basically it should store the last raw request and response that is actually put on the wire (rtu or tcp) that can be read after each transmission/reception. IE:

int modbus_last_raw_query(modbus_t *mb_param, uint8_t *rawQuery);
int modbus_last_raw_response(modbus_t *mb_param, uint8_t *rawResponse);

fix compilation with Visual C++

Microsoft Visual C++ 2008/2010 does not have a ssize_t.
Please apply.

Regards

oldfaber

--- libmodbus-3.0.2\src\modbus-private.h 2012-01-25 05:29:36.000000000 +0100
+++ libmodbus-3.0.2-new\src\modbus-private.h 2012-04-17 17:58:15.308796300 +0200
@@ -25,6 +25,7 @@
#else

include "stdint.h"

include <time.h>

+typedef int ssize_t;
#endif
#include <sys/types.h>
#include <config.h>

Bug in function 0x17 (FC_READ_AND_WRITE_REGISTERS) in 2.9.1

Hello!

In Modbus_Application_Protocol_V1_1b.pdf there is paragraph that states (page 38):

6.17 23 (0x17) Read/Write Multiple registers
This function code performs a combination of one read operation and one write operation in a
single MODBUS transaction. The write operation is performed before the read.

But in the code we generate responce before writing to registers.

Building on Cygwin

I've successfully built libmodbus master on Cygwin with a few minor modifications. The stumbling block was the configuration flags HAVE_DECL_TIOCSRS485: since there's no Linux kernel present, this flag is guaranteed to be 0 on Cygwin, but it cut out otherwise valid code for both ioctl and part of the modbus_rtu_t structure.

I've included a patch with the changes I made. As a side-note, I modified .gitignore to so *.exe files are ignored as well; this allows building of the test suite without git asking questions.

Included is a patch detailing the changes from master I've made to fix the problem. This may not be the correct way to go about these changes—C is not my language of choice, so I may be unaware of particular conventions or subtle language pitfalls.

diff --git a/.gitignore b/.gitignore
index ddd7705..a41c5a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,14 +30,14 @@ modbus-version.h
 stamp-h1
 *.o
 *~
-tests/bandwidth-client
-tests/bandwidth-server-many-up
-tests/bandwidth-server-one
-tests/random-test-client
-tests/random-test-server
-tests/unit-test-client
-tests/unit-test-server
-tests/version
+tests/bandwidth-client*
+tests/bandwidth-server-many-up*
+tests/bandwidth-server-one*
+tests/random-test-client*
+tests/random-test-server*
+tests/unit-test-client*
+tests/unit-test-server*
+tests/version*
 doc/*.html
 doc/*.3
 doc/*.7
diff --git a/src/modbus-rtu-private.h b/src/modbus-rtu-private.h
index d0bc615..3e19dc8 100644
--- a/src/modbus-rtu-private.h
+++ b/src/modbus-rtu-private.h
@@ -84,8 +84,8 @@ typedef struct _modbus_rtu {
 #endif
 #if HAVE_DECL_TIOCSRS485
     int serial_mode;
-    int rts;
 #endif
+    int rts;
 } modbus_rtu_t;

 #endif /* _MODBUS_RTU_PRIVATE_H_ */
diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c
index d694bb6..7e1a71b 100644
--- a/src/modbus-rtu.c
+++ b/src/modbus-rtu.c
@@ -31,8 +31,11 @@
 #include "modbus-rtu.h"
 #include "modbus-rtu-private.h"

-#if HAVE_DECL_TIOCSRS485
+#if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
+#endif
+
+#if HAVE_LINUX_SERIAL_H
 #include <linux/serial.h>
 #endif

modbus device with prefix bytes

I found some devices that can be accessed by modbus, where the response have some (1 or 2 for now) byte containing zero value.
In this case the prefix bytes can be discarded in order to get the real answer.

modbus_rtu_set_serial_mode() need to be called after modbus_connect()

modbus_rtu_set_serial_mode() needs to be called after modbus_connect(). Can't find this information in the documentation. Another option is to change the function modbus_rtu_set_serial_mode() to be able to be called as long as there is a valid modbus_t* and have modbus_connect() to obey and set the mode as well.
Regards

winsock2.h issue on cygwin and win 7

checking winsock2.h usability... no
checking winsock2.h presence... yes
configure: WARNING: winsock2.h: present but cannot be compiled
configure: WARNING: winsock2.h: check for missing prerequisite headers?
configure: WARNING: winsock2.h: see the Autoconf documentation
configure: WARNING: winsock2.h: section "Present But Cannot Be Compiled"
configure: WARNING: winsock2.h: proceeding with the compiler's result
configure: WARNING: ## -----------------------------------------------------
------ ##
configure: WARNING: ## Report this to https://github.com/stephane/libmodbus/
issues ##
configure: WARNING: ## -----------------------------------------------------
------ ##
checking for winsock2.h... no
checking whether TIOCSRS485 is declared... no
configure: creating ./config.status

problem with winsock2.h and configure ?

the command ./configure send me a warning telling me to come here and report what's happened:
"
configure: WARNING: winsock2.h: present but cannot be compiled
configure: WARNING: winsock2.h: check for missing prerequisite headers?
configure: WARNING: winsock2.h: see the Autoconf documentation
configure: WARNING: winsock2.h: section "Present But Cannot Be Compiled"
configure: WARNING: winsock2.h: proceeding with the compiler's result
configure: WARNING: ## ----------------------------------------------------------- ##
configure: WARNING: ## Report this to https://github.com/stephane/libmodbus/issues ##
configure: WARNING: ## ----------------------------------------------------------- ##
"

modbus_reply() doesn't check max read/write register counts.

As discussed on IRC Sept. 22 2011, the title says it all.
Please find a patch suggestion attached.

From 58cf895 Mon Sep 17 00:00:00 2001
From: Josef Holzmayr [email protected]
Date: Thu, 22 Sep 2011 14:31:39 +0200
Subject: [PATCH] Add register count checks to modbus_reply

Add checks so modbus_reply returns a
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS if the count of requested

registers exceeds the spec as noted in modbus.h, line 73ff.

src/modbus.c | 22 +++++++++++++++-------
1 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/modbus.c b/src/modbus.c
index 2860d29..64b9d92 100644
--- a/src/modbus.c
+++ b/src/modbus.c
@@ -662,7 +662,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
case _FC_READ_COILS: {
int nb = (req[offset + 3] << 8) + req[offset + 4];

  •    if ((address + nb) > mb_mapping->nb_bits) {
    
  •    if ((address + nb) > mb_mapping->nb_bits ||
    
  •       nb > MODBUS_MAX_READ_REGISTERS) {
         if (ctx->debug) {
             fprintf(stderr, "Illegal data address %0X in read_bits\n",
                     address + nb);
    

    @@ -684,7 +685,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
    * function) */
    int nb = (req[offset + 3] << 8) + req[offset + 4];

  •    if ((address + nb) > mb_mapping->nb_input_bits) {
    
  •    if ((address + nb) > mb_mapping->nb_input_bits ||
    
  •       nb > MODBUS_MAX_READ_REGISTERS) {
         if (ctx->debug) {
             fprintf(stderr, "Illegal data address %0X in read_input_bits\n",
                     address + nb);
    

    @@ -704,7 +706,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
    case _FC_READ_HOLDING_REGISTERS: {
    int nb = (req[offset + 3] << 8) + req[offset + 4];

  •    if ((address + nb) > mb_mapping->nb_registers) {
    
  •    if ((address + nb) > mb_mapping->nb_registers ||
    
  •       nb > MODBUS_MAX_READ_REGISTERS) {
         if (ctx->debug) {
             fprintf(stderr, "Illegal data address %0X in read_registers\n",
                     address + nb);
    

    @@ -729,7 +732,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
    * function) */
    int nb = (req[offset + 3] << 8) + req[offset + 4];

  •    if ((address + nb) > mb_mapping->nb_input_registers) {
    
  •    if ((address + nb) > mb_mapping->nb_input_registers ||
    
  •       nb > MODBUS_MAX_READ_REGISTERS) {
         if (ctx->debug) {
             fprintf(stderr, "Illegal data address %0X in read_input_registers\n",
                     address + nb);
    

    @@ -797,7 +801,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
    case _FC_WRITE_MULTIPLE_COILS: {
    int nb = (req[offset + 3] << 8) + req[offset + 4];

  •    if ((address + nb) > mb_mapping->nb_bits) {
    
  •    if ((address + nb) > mb_mapping->nb_bits ||
    
  •       nb > MODBUS_MAX_WRITE_REGISTERS) {
         if (ctx->debug) {
             fprintf(stderr, "Illegal data address %0X in write_bits\n",
                     address + nb);
    

    @@ -819,7 +824,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
    case _FC_WRITE_MULTIPLE_REGISTERS: {
    int nb = (req[offset + 3] << 8) + req[offset + 4];

  •    if ((address + nb) > mb_mapping->nb_registers) {
    
  •    if ((address + nb) > mb_mapping->nb_registers ||
    
  •       nb > MODBUS_MAX_WRITE_REGISTERS) {
         if (ctx->debug) {
             fprintf(stderr, "Illegal data address %0X in write_registers\n",
                     address + nb);
    

    @@ -873,7 +879,9 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
    int nb_write = (req[offset + 7] << 8) + req[offset + 8];

     if ((address + nb) > mb_mapping->nb_registers ||
    
  •        (address_write + nb_write) > mb_mapping->nb_registers) {
    
  •        (address_write + nb_write) > mb_mapping->nb_registers ||
    
  •       nb > MODBUS_MAX_RW_WRITE_REGISTERS ||
    
  •       nb_write > MODBUS_MAX_RW_WRITE_REGISTERS) {
         if (ctx->debug) {
             fprintf(stderr,
                     "Illegal data read address %0X or write address %0X write_and_read_registers\n",
    

    --
    1.7.4.1

assertion failure in "modbus-rtu.c"

When I compile and run the following code:

include

include "modbus.h"

include "modbus-rtu.h"

include <errno.h>

include

using namespace std;
int main(){
modbus_t *ctx;
uint16_t tab_reg[64];
int rc;
int i;
ctx = modbus_new_rtu("/dev/ttyS3", 115200, 'N', 8, 1);
if (ctx == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
return -1;
}
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
rc = modbus_read_registers(ctx, 0, 10, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
for (i=0; i < rc; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}

I get the following error:

assertion "ctx->slave != -1" failed: file "modbus-rtu.c", line 119, function: _modbus_rtu_build_request_basis
Aborted (core dumped)

What am I doing wrong?

How to read/write the 6xxxx register ?

How can i read/write 6xxxx holding register ?
if i use modbus_read_registers function, which value i have to set in addr ?

The request i have to send is:
function - 03
Start Addr HI - EA
Start Addr Lo - 6A
Q.ty Reg. Hi - 00
Q.ty Reg. Lo - 1B

Serial_rtu

Thanks Sk3

unit test server fails for bad error reponse test case

When i was testing the libmodbus 2.9.3 , i observed the following error in the server

Waiting for a indication...
<11><03><00><9E><00><1E><7E>
ERROR CRC received 1E7E != CRC calculated 2ECC
Quit the loop: Invalid CRC

and iwith client

TEST MANUAL EXCEPTION:
[11][03][00][6C][00][03][C7][46]
Waiting for a confirmation...
<11><03><06><02><2B><00><00><00><00><51>

  • modbus_read_registers at special address: FAILED

I made it working by adding modbus_flush at the end of the loop.

Regards
harish

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.