瀏覽代碼

Add the support to RTS signal in order to have RS485 working on some linux box with RS485 on-board.

Torello Querci 13 年之前
父節點
當前提交
bf6718c9b1
共有 3 個文件被更改,包括 76 次插入1 次删除
  1. 5 0
      src/modbus-rtu-private.h
  2. 65 1
      src/modbus-rtu.c
  3. 6 0
      src/modbus-rtu.h

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

@@ -80,7 +80,12 @@ typedef struct _modbus_rtu {
 #endif
 #if HAVE_DECL_TIOCSRS485
     int serial_mode;
+    int usage_rts;
 #endif
 } modbus_rtu_t;
 
+/* Time waited beetween the RTS switch before transmit data o after transmit data before to read */
+#define TIME_BETWEEN_RTS_SWITCH  10000
+void _modbus_rtu_setrts(int fd, int on);
+
 #endif /* _MODBUS_RTU_PRIVATE_H_ */

+ 65 - 1
src/modbus-rtu.c

@@ -264,7 +264,21 @@ ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)
     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);
+    modbus_rtu_t *ctx_rtu = ctx->backend_data;
+    if (ctx_rtu->usage_rts == MODBUS_USE_RTS) {
+        ssize_t size;
+
+        _modbus_rtu_setrts(ctx->s,1);
+        usleep(TIME_BETWEEN_RTS_SWITCH);
+
+        size = write(ctx->s, req, req_length);
+        usleep(TIME_BETWEEN_RTS_SWITCH);
+        _modbus_rtu_setrts(ctx->s,0);
+
+        return size;
+    } else {
+        return write(ctx->s, req, req_length);
+    }
 #endif
 }
 
@@ -703,6 +717,10 @@ static int _modbus_rtu_connect(modbus_t *ctx)
 #if HAVE_DECL_TIOCSRS485
     /* The RS232 mode has been set by default */
     ctx_rtu->serial_mode = MODBUS_RTU_RS232;
+
+    /* The RTS usage has been set by default */
+    ctx_rtu->usage_rts = MODBUS_NO_USE_RTS;
+
 #endif
 
     return 0;
@@ -764,6 +782,38 @@ int modbus_rtu_get_serial_mode(modbus_t *ctx) {
     }
 }
 
+int modbus_rtu_set_usage_rts(modbus_t *ctx, int mode)
+{
+    if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
+        modbus_rtu_t *ctx_rtu = ctx->backend_data;
+        
+        if (mode == MODBUS_NO_USE_RTS || mode == MODBUS_USE_RTS ) {
+            ctx_rtu->usage_rts = mode;
+            return 0;
+        }
+
+        if (ctx->debug) {
+            fprintf(stderr, "This function isn't supported on your platform\n");
+        }
+        errno = ENOTSUP;
+        return -1;
+    }
+
+    /* Wrong backend and invalid mode specified */
+    errno = EINVAL;
+    return -1;
+}
+
+int modbus_rtu_get_usage_rts(modbus_t *ctx) {
+    if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
+        modbus_rtu_t *ctx_rtu = ctx->backend_data;
+        return ctx_rtu->usage_rts;
+    } else {
+        errno = EINVAL;
+        return -1;
+    }
+}
+
 void _modbus_rtu_close(modbus_t *ctx)
 {
     /* Closes the file descriptor in RTU mode */
@@ -915,3 +965,17 @@ modbus_t* modbus_new_rtu(const char *device,
 
     return ctx;
 }
+
+void _modbus_rtu_setrts(int fd, int on)
+{
+    int controlbits;
+
+    ioctl(fd, TIOCMGET, &controlbits);
+    if (on) {
+        controlbits |= TIOCM_RTS;
+    } else {
+      controlbits &= ~TIOCM_RTS;
+    }
+    ioctl(fd, TIOCMSET, &controlbits);
+}
+

+ 6 - 0
src/modbus-rtu.h

@@ -32,7 +32,13 @@ modbus_t* modbus_new_rtu(const char *device, int baud, char parity,
 #define MODBUS_RTU_RS232 0
 #define MODBUS_RTU_RS485 1
 
+#define MODBUS_NO_USE_RTS 0
+#define MODBUS_USE_RTS    1
+
 int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
 int modbus_rtu_get_serial_mode(modbus_t *ctx);
 
+int modbus_rtu_set_usage_rts(modbus_t *ctx, int mode);
+int modbus_rtu_get_usage_rts(modbus_t *ctx);
+
 #endif /* _MODBUS_RTU_H_ */