فهرست منبع

Add functions to set/get RS485 communications on Linux

Stéphane Raimbault 14 سال پیش
والد
کامیت
9bf8309597
5فایلهای تغییر یافته به همراه63 افزوده شده و 2 حذف شده
  1. 2 1
      NEWS
  2. 1 0
      configure.ac
  3. 1 0
      src/modbus-rtu-private.h
  4. 50 1
      src/modbus-rtu.c
  5. 9 0
      src/modbus-rtu.h

+ 2 - 1
NEWS

@@ -18,7 +18,8 @@ libmodbus 2.9.4 (2011-05-XX)
     * modbus_set_timeout_begin -> modbus_set_response_timeout
     * modbus_get_timeout_end -> modbus_get_byte_timeout
     * modbus_set_timeout_end -> modbus_set_byte_timeout
-
+- New functions modbus_set/get_serial_mode by Manfred Gruber and Stéphane
+  Raimbault for RS485 communications
 
 libmodbus 2.9.3 (2011-01-14)
 ============================

+ 1 - 0
configure.ac

@@ -77,6 +77,7 @@ AC_CHECK_HEADERS([ \
     netinet/tcp.h \
     arpa/inet.h \
     netdb.h \
+    linux/serial.h \
 ])
 
 # Check whether to build docs / install man pages

+ 1 - 0
src/modbus-rtu-private.h

@@ -74,6 +74,7 @@ typedef struct _modbus_rtu {
 #else
     /* Save old termios settings */
     struct termios old_tios;
+    int serial_mode;
 #endif
 } modbus_rtu_t;
 

+ 50 - 1
src/modbus-rtu.c

@@ -30,6 +30,11 @@
 #include "modbus-rtu.h"
 #include "modbus-rtu-private.h"
 
+#if defined(linux)
+#include <sys/ioctl.h>
+#include <linux/serial.h>
+#endif
+
 /* Table of CRC values for high-order byte */
 static const uint8_t table_crc_hi[] = {
     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
@@ -692,11 +697,55 @@ static int _modbus_rtu_connect(modbus_t *ctx)
     if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
         return -1;
     }
-#endif
 
+    /* The RS232 mode has been set by default */
+    ctx_rtu->serial_mode = MODBUS_RTU_RS232;
+#endif
     return 0;
 }
 
+#if defined(linux)
+int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode)
+{
+    if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
+        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) {
+                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;
+        }
+    }
+
+    /* Wrong backend and invalid mode specified */
+    errno = EINVAL;
+    return -1;
+}
+
+int modbus_rtu_get_serial_mode(modbus_t *ctx) {
+    if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
+        modbus_rtu_t *ctx_rtu = ctx->backend_data;
+        return ctx_rtu->serial_mode;
+    } else {
+        errno = EINVAL;
+        return -1;
+    }
+}
+#endif
+
 void _modbus_rtu_close(modbus_t *ctx)
 {
     /* Closes the file descriptor in RTU mode */

+ 9 - 0
src/modbus-rtu.h

@@ -28,4 +28,13 @@
 modbus_t* modbus_new_rtu(const char *device, int baud, char parity,
                          int data_bit, int stop_bit);
 
+#if defined(linux)
+/* On Linux, we can tell the kernel for RS485 communication */
+#define MODBUS_RTU_RS232 0
+#define MODBUS_RTU_RS485 1
+
+int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
+int modbus_rtu_get_serial_mode(modbus_t *ctx);
+#endif
+
 #endif /* _MODBUS_RTU_H_ */