I can't set RS485 mode ("Bad file descriptor" or "Invalid argument")

6,963 views
Skip to first unread message

Matías Fabián Salomón

unread,
Jul 18, 2012, 8:59:22 AM7/18/12
to libm...@googlegroups.com
Hi, I will try be short.

I have this code

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus.h>
int main(int argc, char*argv[])
{
    int socket;
    modbus_t *ctx;
    int rc;
    uint8_t *query;
    int header_length;

    //...

    ctx = modbus_new_rtu("/dev/ttyS1", 19200, 'N', 8, 1);
    modbus_set_slave(ctx, SERVER_ID);
    query = malloc(MODBUS_RTU_MAX_ADU_LENGTH);
    header_length = modbus_get_header_length(ctx);
    modbus_set_debug(ctx, TRUE);

    //...

    if (modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_DOWN) == -1)
        fprintf(stderr, "(2) Unable to set rts: %s\n", modbus_strerror(errno));
    if (modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485) == -1)
        fprintf(stderr, "(3) Unable to set mode: %s\n", modbus_strerror(errno)); // <- Allways error here: "Bad file descriptor"
    rc = modbus_connect(ctx);
    if (rc == -1) {
        fprintf(stderr, "(1) Unable to connect %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    if (modbus_rtu_get_serial_mode(ctx) == MODBUS_RTU_RS485)
        fprintf(stderr, "(!) Modo Correcto\n");
    else
        fprintf(stderr, "(!) Modo Incorrecto\n"); // <- Allways  show this. Incorrect mode.




Y also try changing the sentences order

    rc = modbus_connect(ctx);
    if (rc == -1) {
        fprintf(stderr, "(1) Unable to connect %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    if (modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_DOWN) == -1)
        fprintf(stderr, "(2) Unable to set rts: %s\n", modbus_strerror(errno));
    if (modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485) == -1)
        fprintf(stderr, "(3) Unable to set mode: %s\n", modbus_strerror(errno)); // <- Allways error here: "Invalid argument"
    if (modbus_rtu_get_serial_mode(ctx) == MODBUS_RTU_RS485)
        fprintf(stderr, "(!) Modo Correcto\n");
    else
        fprintf(stderr, "(!) Modo Incorrecto\n"); // <- Allways  show this. Incorrect mode.



So... can anybody helpme? I don't ask resolve my problem, just send me a tip, a clue. Or, if you have, a simple RS485 Test Code so I can try yo use it.

Thanks for read.
Have a nice day.



saurabh shah

unread,
Jul 18, 2012, 11:51:38 AM7/18/12
to libm...@googlegroups.com
Hi Matias!
Just a small tip : there are a few Qt-based frontend implentations of libmodus; you can check them out. "QModbus" and "QModMaster" Both of them work well with RS485. Search on google for them.

Best Regards
Saurabh

Matías Fabián Salomón

unread,
Jul 18, 2012, 12:15:04 PM7/18/12
to libm...@googlegroups.com
I install it, and try to use, but it isn't work for me :(

It allways sendme a "time out" error. And I can't find where set RS-485 mode.

I don't know anything about this :( I'm so sad.

Maybe, maybe, my hardware connection is bad, and it never will works. 

Know you how can I test my hardware connection?

Thanks for try to help me.

2012/7/18 saurabh shah <shahsau...@gmail.com>

saurabh shah

unread,
Jul 18, 2012, 3:14:04 PM7/18/12
to libm...@googlegroups.com
Hi Matias;
which platform are you using? Windows or Linux?
In the modbus-rtu.c ; there are some missing flags which need to be implemented according to your hardware.
Once you set the flags properly; your RS 485 should work

Matías Fabián Salomón

unread,
Jul 18, 2012, 3:20:02 PM7/18/12
to libm...@googlegroups.com
I'm on Linux, Ubuntu 10.04, and using the libmodbus 3.1 (the last version).

I don't see anything about the RS485 on the documentation. Can you tell me where need I set the the RS485 config?

Thanks again.

saurabh shah

unread,
Jul 18, 2012, 3:37:08 PM7/18/12
to libm...@googlegroups.com
https://github.com/stephane/libmodbus/blob/master/src/modbus-rtu.c 
This is the file you should be looking to work with.
I also faced a timeout error with my RS485 ; but setting the RTS Control flag worked for me[I am on windows]
If RTS Control is your problem; read the following link to get started

Matías Fabián Salomón

unread,
Jul 19, 2012, 8:22:39 AM7/19/12
to libm...@googlegroups.com
Hi, I'm reading and trying, it isn't work yet... but I'm working.

I have info to read and test, I will notice you when I'm loose again :)

2012/7/18 saurabh shah <shahsau...@gmail.com>

Matías Fabián Salomón

unread,
Jul 20, 2012, 8:55:48 AM7/20/12
to libm...@googlegroups.com
So, it isn't working.

Maybe... need I enable something on my kernel? I can't figure what or how.

The problem is here

modbus-rtu.c : lines 727-731

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

in the line 729 it returns -1, and errno is setted to 22 (Invalid argument).
I think this is because I have a bad configuration in some place, but I don't know where.




Message has been deleted

saurabh shah

unread,
Jul 21, 2012, 3:38:09 AM7/21/12
to libm...@googlegroups.com
It seems your problem lies in incorrect settings for  "rs485conf.flags" 
Try
rs485conf.flags |= SER_RS485_ENABLED;
Also there are a few other flags you can set for rs485conf. Here is what I found on linux documentation pages::

 /* Set logical level for RTS pin equal to 1 when sending: */
 rs485conf.flags |= SER_RS485_RTS_ON_SEND;
 /* or, set logical level for RTS pin equal to 0 when sending: */
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
 /* Set logical level for RTS pin equal to 1 after sending: */
 rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
 /* or, set logical level for RTS pin equal to 0 after sending: */
 rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
/* Set rts delay before send, if needed: */
 rs485conf.delay_rts_before_send = ...;
/* Set rts delay after send, if needed: */
rs485conf.delay_rts_after_send = ...;
 /* Set this flag if you want to receive data even whilst sending data */
rs485conf.flags |= SER_RS485_RX_DURING_TX;

Set whatever flags according to whatever you need for Hardware Flow Control.

Matías Fabián Salomón

unread,
Jul 23, 2012, 7:26:08 AM7/23/12
to libm...@googlegroups.com
Ok, I will to try. I'm doing this right now.

Just to know rs485conf.delay_rts_before_send  and rs485conf.delay_rts_after_send  must be setted in msec, right?

And "rs485conf.flags |= SER_RS485_RX_DURING_TX;" it's for real RS-485 I mean half duplex. Because I have 485, not 422 (full duplex), and I don't know if I need to set anything more.

I'm trying and will post the results.

Thanks again.

Matías Fabián Salomón

unread,
Jul 23, 2012, 7:48:06 AM7/23/12
to libm...@googlegroups.com
Me again.

First, I try with the four combination, (0,0), (0,1), (1,0), (1,1) and it is doesn't work.

And second, gcc return an erro when I try to set delay_rts_after_send, he say it isn't declarated (error: ‘struct serial_rs485’ has no member named ‘delay_rts_after_send’
).

Maybe have I a bad .h file? it use "linux/serial.h".

So, I keep trying.

saurabh shah

unread,
Jul 23, 2012, 10:58:59 AM7/23/12
to libm...@googlegroups.com
Hi Matias; Take a look at the following patch

+ Some serial communications devices are half-duplex and require + a signal to give the required direction of communications. + + One common example of this is when using a MAX202 - MAX485 chip + pair (or similar) as a bridge between a RS232 interface and a + RS485 interface. + + Another example is when using simple radio modems, which may have a + further requirement that the direction should be asserted for a + specified time before transmission, and held for a specified time + after packet transmission. + + Select this option to enable kernel control of the handshaking + lines to give direction control. This will make a serial port + ioctl (TIOCSRS485) available for enabling this feature as well as + for configuration of handshaking line to use (RTS or DTR), + the sense of the line, and pre and post transmission delays. +

saurabh shah

unread,
Jul 23, 2012, 11:06:57 AM7/23/12
to libm...@googlegroups.com
Also; I do not know what hardware you have; but one very simple way to check your hardware for RS485 is connect to a Windows machine; and use
"Modbus poll". If it works; then half the problem is solved

Matías Fabián Salomón

unread,
Jul 24, 2012, 7:57:25 AM7/24/12
to libm...@googlegroups.com
I'm doing that.

I have a Windows Notebook, with a USB/Serial and a RS-232/RS-485 converter microaxial.

So I will install a VirtualBox with a Windows and use a ModBus program to test the port... I hope this work, else I will to try get some HD and install a native Windows and again try.

I sent an email to the factory (Advantech) asking instructions to test the RS-485 port on COM2.

I will keep you informed. 

Matías Fabián Salomón

unread,
Jul 25, 2012, 7:46:00 AM7/25/12
to libm...@googlegroups.com
OK people, maybe, maybe my RS-485 port isn't working.

I install Windows and use a program (ModSim) and connect with other computer with Windows and ModScan.

The other PC haven't a COM port, so I install a USB to Serial (Manhatan), and add a RS-485/RS-232 Microaxial.

I try to connect directly with the RS-485 (COM2) but it doesn't work, so I install another one USB/Serial and add a new RS-485/RS232 Microaxial, and it works.

With the same configuration, over the COM2 (Native RS-485) doesn't works, but it works with the COM3 (USB to Serial + RS-485/RS-232 Microaxial).

So, I think the COM2 is bad. We say "burned" when a Port doesn't works, I don't know how you say.

I try a configuration on BIOS SETUP, enabling and disabling the AutoFlowControl, and in both cases doesn't work over RS-485.

I will to try install the USB/Serial adapter on Linux and test libmodbus with this. I hope it works now.

I will send the result over here,

Merci beaucoup!

kunjanshah

unread,
Oct 9, 2012, 12:37:43 AM10/9/12
to libm...@googlegroups.com

Hi Matías,

I am also facing the same problem for RS-485 communication using libmodbus library.

I have tried both things:

case 1:

ioctl(fd, TIOCMGET, &flags);
flags &= ~TIOCM_RTS;
ioctl(fd, TIOCMSET, T, &flags);

write(fd, buffer_to_send, sizeof(buffer_to_send));
delay( );

ioctl(fd, TIOCMGET, &flags);
flags |= TIOCM_RTS;
ioctl(fd, TIOCMSET, &flags);


case 2:

         struct serial_rs485 rs485conf;
 
         /* Enable RS485 mode: */
         rs485conf.flags |= SER_RS485_ENABLED;


        rs485conf.delay_rts_before_send = 0;

        rs485conf.delay_rts_after_send = 0;

        ioctl (fd, TIOCSRS485, &rs485conf)

But in both the cases I didn't get successful result.

In first case some delay is required. And it will very according to baudrate.

I have connected RTS pin to MAX-485 Enable pin.

I think you have done lots of R&D on it. So, you are the best person who can guide me.

Please send me sample code of RS-485 if you have.

Or guide me how to proceed for it.

Thanks in advance.

regards,
Kunjan Shah

Stéphane Raimbault

unread,
Oct 9, 2012, 4:19:57 AM10/9/12
to libm...@googlegroups.com
For me, RS485 is a bit of black magic, and I've never used RS485 devices! That why I need testers each time I change something in this front ;)
RS485 communication is a mess (bad hardware, incomplete driver, many ways to set up the communication, etc) and to help you (or mislead you), libmodbus try to enable SER_RS485_ENABLED when you want to use RS485 but I'm pretty sure it's not sufficient:

http://lxr.free-electrons.com/source/include/linux/serial.h#L206

struct serial_rs485 {
        __u32   flags;                  /* RS485 feature flags */
#define SER_RS485_ENABLED               (1 << 0)        /* If enabled */
#define SER_RS485_RTS_ON_SEND           (1 << 1)        /* Logical level for
                                                           RTS pin when
                                                           sending */
#define SER_RS485_RTS_AFTER_SEND        (1 << 2)        /* Logical level for
                                                           RTS pin after sent*/
#define SER_RS485_RX_DURING_TX          (1 << 4)
        __u32   delay_rts_before_send;  /* Delay before send (milliseconds) */
        __u32   delay_rts_after_send;   /* Delay after send (milliseconds) */
        __u32   padding[5];             /* Memory is cheap, new structs
                                           are a royal PITA .. */
};

because you'll certainly need to enable SER_RS485_RTS_ON_SEND or SER_RS485_RTS_AFTER_SEND and to adjust delays.

Another way to proceed is to manually set RTS (modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP or DOWN)), but on this front too, it could be necessary to extend API to give access to delays or DTR pin.

I need feedback to extend libmodbus API on these points.

Stéphane

kunjanshah

unread,
Oct 9, 2012, 7:59:06 AM10/9/12
to libm...@googlegroups.com
Dear Stephene,

Thanks for joining us.

Please go through the below link. I just want to make my waveform as shown in below link.

http://www.acmesystems.it/28

After debugging I found that in function

modbus_rtu_set_serial_mode( )
{


            if (mode == MODBUS_RTU_RS485) {
                rs485conf.flags = SER_RS485_ENABLED;
            if (ioctl(ctx->s, TIOCSRS485, &rs485conf) < 0) {         //Getting -1  here
                return -1;
            }
}

In my library (3.0.3), I have no functions like modbus_rtu_set_rts( ). I have also tried to replace modbus-rtu.c file but failed to replace it.

https://github.com/stephane/libmodbus/blob/master/src/modbus-rtu.c

Please mention that what kind of inputs are required.

Please try to find out the solution as soon as possible.

Thanks and regards,
Kunjan Shah

Steve Kelly

unread,
Oct 26, 2012, 12:36:25 AM10/26/12
to libm...@googlegroups.com
Gents,

I am working on the same problem and have advanced a little further. But unfortunately I havent had time to completely fix my problem.
The RTS did little to help my situation, I found that it was the DTR which actually enabled the transmitter on my USB->RS485 converter.

But I am currently dropping characters on the receive and think it has something to do with the timing involved with the disabling of DTR and RTS. Will let you know how I go when I get back onto it.

Steve

Alex

unread,
Dec 15, 2013, 2:46:02 PM12/15/13
to libm...@googlegroups.com
I am working on setting up a modbus line on a raspberry pi, and am unable to get past setting the serial mode (modbus_rtu_set_serial_mode) returns the bad file descriptor error. Did anyone manage to get past this error? Any help would be greatly appreciated.

HS

unread,
Jun 6, 2014, 3:05:02 PM6/6/14
to libm...@googlegroups.com, versi...@gmail.com
I am also unable to get past setting the serial mode (modbus_rtu_set_serial_mode) for RS485.  It returns the bad file descriptor error.  Has anyone resolved this?  

I noticed in modbus-rtu.c, there is: 

#if HAVE_DECL_TIOCSRS485

in the code for function modbus_rtu_set_serial_mode.  

Where is this set?  I'm wondering if this hasn't been set and that's why RS485 isn't working...
Thanks in advance!

Stéphane Raimbault

unread,
Jun 25, 2014, 5:14:46 PM6/25/14
to libm...@googlegroups.com
This Linux support of RS485 device is a big lie, I think is it only to support one device in the world so it's misleading for many libmodbus users.

I don't use RS485 myself and it would be very cool if someone could hep me to write a guide to explain how to use RS485 with libmodbus.

PS: I hope to be able to dedicate a few days to the project in 10 days...


--
Vous recevez ce message, car vous êtes abonné au groupe Google Groupes "libmodbus".
Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le concernant, envoyez un e-mail à l'adresse libmodbus+...@googlegroups.com.
Pour obtenir davantage d'options, consultez la page https://groups.google.com/d/optout.

Sébastien Le Fur

unread,
Sep 24, 2014, 4:54:31 AM9/24/14
to libm...@googlegroups.com
Hello Stephane,

I use the libmodbus under linux with ModBus RTU and RS485.

i have drive the module ADAM with this Library Libmodbus but with the serial RS232 , thanks to a adaptator RS485/RS232.

On my PC automate, two ports can be used in RS485. These ports is validate and tested under Windows.

I try to use via lidmodbus RTU and RS485 serial.
For this moment,the result is no good. The function "modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485) return -1 .

A solution have been found ?

NB: I have all the environnement to test it via RS485.

Thanks a lot. 
Sebastien

Steve Kelly

unread,
Sep 24, 2014, 8:00:25 AM9/24/14
to libm...@googlegroups.com
Hi Sebastien

I use Libmodbus on a linux platform with RS485 and it all works great. I have about 12 threads running all using different serial ports reading data from modbus devices into a database.

Here is some very basic cutdown code which should work for you (no error checking included):

modbus_t *ctx;
uint16_t input_reg[128];  //number of registers required

ctx =  modbus_new_rtu('/dev/ttyUSB0', 19200, 'N', 8, 1);    //where /dev/ttyUSB0 is your serial port, 19200 is your buad rate, No parity, 8 data bits and 1 stop bit
modbus_rtu_set_serial_mode(ctx, 1); This is the same as your MODBUS_RTU_RS485 but I had issues using that in early versions hence the 1.
if (modbus_connect(ctx) == -1)
  // handle error here
modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_NONE);  // not really needed unless you want to use RTS such as RTS_UP or RTS_DOWN

response_timeout.tv_sec = 0;   //set some default timeouts in secs
response_timeout.tv_usec = 500000;  //set some default timeouts in usec
modbus_set_response_timeout(ctx, &response_timeout);

modbus_set_debug(ctx, TRUE);   //turn on debug if needed

while (1) {
   //poll your slave devices here....
   modbus_flush(ctx);  //flush any previous data
   modbus_set_slave(ctx, address);    //set slave address to be used

   rc = modbus_read_input_registers(ctx, start_reg, no_of_reg, input_reg);  //Read some Input Registers
}

modbus_close(ctx);
modbus_free(ctx);

Sébastien Le Fur

unread,
Sep 24, 2014, 9:25:25 AM9/24/14
to libm...@googlegroups.com
Hi sk2209,

Thanks for your answer.

I use the same code to drive the UART in RS485 ( /dev/ttyS4, 115200 bauds, No parity , 8 data bits and 1 stop bit )

The problem is than the retuen valueis -1 for this command " modbus_rtu_set_serial_mode(ctx, 1);".

It seems to refuse to set serial mode in RS485.

The port is configured in RS485 auto in the bios , under windows the communication is successful.( just to validate the port :) ).

Steve Kelly

unread,
Sep 24, 2014, 7:41:55 PM9/24/14
to libm...@googlegroups.com
I must admit I have never checked the return code on that.

Sent from my iPhone

Stéphane Raimbault

unread,
Sep 25, 2014, 5:24:33 AM9/25/14
to libm...@googlegroups.com
Hi Kunjan,

You provided information about the way to handle your ATMEL device.
Have you been able to set up your device as recommended by ATMEL?

In your code, you can use something like that to set up your RS485 device (it's not specific to ATMEL):

int fd;
int status;
struct rs485_ctrl ctrl485;

ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'N', 8, 1);
modbus_set_slave(ctx, SERVER_ID);
modbus_connect(ctx);

// Extract the file descriptor to apply custom tweaks
fd = modbus_get_socket(ctx);

// Extract from http://www.acmesystems.it/28
// Set the serial port in 485 mode
  ctrl485.rts_on_send = 0;           // It means that DE is at 3.3 volt on send
  ctrl485.rts_after_sent = 1;        // It means that DE is at 0 volt on send
  ctrl485.delay_rts_before_send = 0; // DE will be active at same time of data
  ctrl485.enabled = 1;
  status = ioctl(fd, TIOCSERSETRS485, &ctrl485);  
  if (status) {
    printf("ERROR PORT 1! TIOCSERSETRS485 failed %i", status);
    return -1;
  }

DON'T USE modbus_rtu_set_serial_mode!

Questions:
- I don't know if it's necessary to apply RS485 settings (ctrl485.foo = bar and ioctl call) before the cfsetospeed/tcsetattr calls. If required, libmodbus need a change...
- libmodbus doesn't call cfmakeraw(&ti); before tcsetattr call, is it required or a good thing?

Can someone with a successful RS485 setup with libmodbus can share information, please?

Elvin De Jesus

unread,
Aug 28, 2015, 4:48:29 PM8/28/15
to libmodbus
try 

#include <sys/ioctl.h>
#include <linux/serial.h>
#include <asm/ioctls.h>


    struct serial_rs485 rs485conf;
    // Set RS485 mode:
    if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
            printf("Error: TIOCGRS485 ioctl not supported.\n");
    }
rs485conf.flags &= ~(SER_RS485_RX_DURING_TX);
    rs485conf.flags |= SER_RS485_ENABLED;
    fcntl(fd, F_SETFL, FNDELAY);
    if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
        printf("ioctl error\n");
    }

On Wednesday, July 18, 2012 at 8:59:22 AM UTC-4, Matías Fabián Salomón wrote:
Hi, I will try be short.

I have this code

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus.h>
int main(int argc, char*argv[])
{
    int socket;
    modbus_t *ctx;
    int rc;
    uint8_t *query;
    int header_length;

    //...

    ctx = modbus_new_rtu("/dev/ttyS1", 19200, 'N', 8, 1);
    modbus_set_slave(ctx, SERVER_ID);
Reply all
Reply to author
Forward
0 new messages