Skip to content

Commit 65b86d1

Browse files
Adds validation for echo suppression
1 parent bb13443 commit 65b86d1

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed

src/modbus-rtu-private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ typedef struct _modbus_rtu {
7272
#endif
7373
/* To handle many slaves on the same link */
7474
int confirmation_to_ignore;
75+
/* software-side local echo suppression of sent bytes since hardware
76+
* does not support it or is configured to not do it */
77+
bool is_echo_suppressing;
7578
} modbus_rtu_t;
7679

7780
#endif /* MODBUS_RTU_PRIVATE_H */

src/modbus-rtu.c

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <stdio.h>
1010
#include <stdlib.h>
1111
#include <string.h>
12+
#include <time.h>
1213
#ifndef _MSC_VER
1314
#include <unistd.h>
1415
#endif
@@ -251,6 +252,56 @@ static void _modbus_rtu_ioctl_rts(modbus_t *ctx, int on)
251252
}
252253
#endif
253254

255+
static ssize_t _modbus_rtu_suppress_echo_write(modbus_t *ctx, const uint8_t *req, int req_length) {
256+
ssize_t write_size, read_size, count;
257+
uint8_t req_echo[MODBUS_RTU_MAX_ADU_LENGTH];
258+
time_t start_time;
259+
260+
write_size = write(ctx->s, req, req_length);
261+
262+
read_size = 0;
263+
count = 0;
264+
start_time = time(NULL);
265+
// Time limit the loop to 3 seconds in case the read continuously returns 0 bytes read
266+
while (read_size < write_size && difftime(time(NULL), start_time) < 3)
267+
{
268+
count += read(ctx->s, &req_echo[read_size], write_size - read_size);
269+
270+
// return immediately on error
271+
if (count < 0) {
272+
return -1;
273+
}
274+
275+
read_size += count;
276+
}
277+
278+
if (ctx->debug)
279+
{
280+
printf("Read back %d bytes echoed from the socket\n", read_size);
281+
for (int i = 0; i < read_size; i++)
282+
{
283+
fprintf(stderr, "|%02X|", req_echo[i]);
284+
}
285+
fprintf(stderr, "\n");
286+
}
287+
288+
for (int i = 0; i < read_size; i++)
289+
{
290+
if (req[i] != req_echo[i])
291+
{
292+
fprintf(stderr,
293+
"ERROR: during echo suppression, sent 0x%02X for byte req[%d] of the request, read back 0x%02X for byte echo[%d] of the echo\n",
294+
req[i],
295+
i,
296+
req_echo[i],
297+
i);
298+
return -1;
299+
}
300+
}
301+
302+
return write_size;
303+
}
304+
254305
static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)
255306
{
256307
#if defined(_WIN32)
@@ -272,15 +323,23 @@ static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_lengt
272323
ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP);
273324
usleep(ctx_rtu->rts_delay);
274325

275-
size = write(ctx->s, req, req_length);
326+
if (!ctx_rtu->is_echo_suppressing) {
327+
size = write(ctx->s, req, req_length);
328+
} else {
329+
size = _modbus_rtu_suppress_echo_write(ctx, req, req_length);
330+
}
276331

277332
usleep(ctx_rtu->onebyte_time * req_length + ctx_rtu->rts_delay);
278333
ctx_rtu->set_rts(ctx, ctx_rtu->rts != MODBUS_RTU_RTS_UP);
279334

280335
return size;
281336
} else {
282337
#endif
283-
return write(ctx->s, req, req_length);
338+
if (!ctx_rtu->is_echo_suppressing) {
339+
return write(ctx->s, req, req_length);
340+
} else {
341+
return _modbus_rtu_suppress_echo_write(ctx, req, req_length);
342+
}
284343
#if HAVE_DECL_TIOCM_RTS
285344
}
286345
#endif
@@ -1089,6 +1148,37 @@ int modbus_rtu_set_rts_delay(modbus_t *ctx, int us)
10891148
}
10901149
}
10911150

1151+
int modbus_rtu_set_suppress_echo(modbus_t* ctx, bool on) {
1152+
if (ctx == NULL) {
1153+
errno = EINVAL;
1154+
return -1;
1155+
}
1156+
1157+
if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
1158+
modbus_rtu_t* rtu = (modbus_rtu_t*) ctx->backend_data;
1159+
rtu->is_echo_suppressing = on;
1160+
return 0;
1161+
}
1162+
1163+
errno = EINVAL;
1164+
return -1;
1165+
}
1166+
1167+
int modbus_rtu_get_suppress_echo(modbus_t* ctx) {
1168+
if (ctx == NULL) {
1169+
errno = EINVAL;
1170+
return -1;
1171+
}
1172+
1173+
if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
1174+
modbus_rtu_t* rtu = (modbus_rtu_t*) ctx->backend_data;
1175+
return rtu->is_echo_suppressing;
1176+
}
1177+
1178+
errno = EINVAL;
1179+
return -1;
1180+
}
1181+
10921182
static void _modbus_rtu_close(modbus_t *ctx)
10931183
{
10941184
/* Restore line settings and close file descriptor in RTU mode */
@@ -1283,6 +1373,7 @@ modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop
12831373
#endif
12841374

12851375
ctx_rtu->confirmation_to_ignore = FALSE;
1376+
ctx_rtu->is_echo_suppressing = FALSE;
12861377

12871378
return ctx;
12881379
}

src/modbus-rtu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifndef MODBUS_RTU_H
88
#define MODBUS_RTU_H
99

10+
#include <stdbool.h>
1011
#include "modbus.h"
1112

1213
MODBUS_BEGIN_DECLS
@@ -40,4 +41,7 @@ MODBUS_API int modbus_rtu_get_rts_delay(modbus_t *ctx);
4041

4142
MODBUS_END_DECLS
4243

44+
int modbus_rtu_set_suppress_echo(modbus_t *ctx, bool on);
45+
int modbus_rtu_get_suppress_echo(modbus_t *ctx);
46+
4347
#endif /* MODBUS_RTU_H */

0 commit comments

Comments
 (0)