stephane/libmodbus — pull request #70 by jaimealsilva (2012-07-03 05:21:06+00:00)
Title: Proxy - modbus_proxy function

Hello there.

Maybe you won't remember by now but about 4 months ago you rejected a pull request of mine because of formatting issues and also because all the changes were made on master instead of branches (I was a new git user). There were two main issues addressed on those changes:

1. Defective hardware that has echo enabled on the RS485 port.
2. Implementing a function to send requests from one context to another (a proxy).

From those features you seemed interested on the proxy one so here I'm sending you another pull request about that one (you can also grab the echo hardware stuff from my echohw branch, if interested).

I finally found the time this weekend to work on this project again and as you suggested I deleted the old fork an moved the changes to a new branch.

This function was developed to solve the following problem: I have a Single Board Computer (SBC) that acts as the master of a MODBUS/RS485 bus and also has an Ethernet port and I wanted to use it as a bridge between Ethernet and RS485 so that is possible to send MODBUS requests from Ethernet to the devices on the RS485 bus.

The following is the program I used to test the function, this one runs on the SBC to connect the Ethernet and RS485 contexts:

```C++
/*
* File: main.cpp
*/

#include
#include
#include

using namespace std;

#ifndef MODBUS_PORT
#define MODBUS_PORT 1502
#endif

inline void debug_msg(string msg) {
#ifdef DEBUG
cerr << msg << endl;
#endif
}

int main(int argc, char** argv) {
modbus_t *tcp_ctx, *rtu_ctx;
string ser_dev;

if (argc > 1)
ser_dev = argv[1];
else
ser_dev = "/dev/ttts2";

/* TCP Context -> Server. IP string doesn't matter since
is changed to INADDR_ANY by modbus_tcp_listen */
tcp_ctx = modbus_new_tcp("0.0.0.0", MODBUS_PORT);
if (!tcp_ctx) {
debug_msg("Can't create TCP context");
exit(1);
}
/* RS485 Context */
rtu_ctx = modbus_new_rtu(ser_dev.c_str(), 38400, 'E', 8, 1);
#ifdef DEBUG
modbus_set_debug(tcp_ctx, 1);
modbus_set_debug(rtu_ctx, 1);
#endif

int socket = modbus_tcp_listen(tcp_ctx, 1);
if (socket < 0) {
debug_msg("Couldn't listen");
exit(1);
}
for (;;) {

/* Connect to slave side */
if (modbus_connect(rtu_ctx) < 0) {
debug_msg("Can't connect to RTU side");
exit (1);
}

debug_msg("Waiting connection ...");
int in_socket = modbus_tcp_accept(tcp_ctx, &socket);
if (in_socket < 0 ) {
debug_msg("Connect failed");
exit(1);
}

for (;;) {
debug_msg("Reading request from TCP/IP ...");
uint8_t tcp_buf[MODBUS_TCP_MAX_ADU_LENGTH];
int tcp_bs = modbus_receive(tcp_ctx, tcp_buf);
if (tcp_bs < 0)
break;

// Send request to RTU slave
tcp_bs = modbus_proxy(tcp_ctx, rtu_ctx, tcp_buf, tcp_bs);
}

debug_msg("Closing connections");
modbus_close(tcp_ctx);
modbus_close(rtu_ctx);
}

return 0;
}
```

Now from any other device connected to the Ethernet network I can read the devices on the RS485 by setting the slave address on the TCP context.