--- a/mb_ascii.c Sun Oct 16 07:10:20 2022 +0100
+++ b/mb_ascii.c Sun Oct 16 14:25:06 2022 +0100
@@ -1452,6 +1452,7 @@
int modbus_ascii_read(int *nd,
+ mb_frame_type_t requested_frame_type, /* ignored by this layer ! */ const struct timespec *recv_timeout) {
--- a/mb_layer1.h Sun Oct 16 07:10:20 2022 +0100
+++ b/mb_layer1.h Sun Oct 16 14:25:06 2022 +0100
@@ -38,6 +38,12 @@
#define MAX_WRITE_REGS 123 /* Function 0x10 */
+/* Data type required for modbus_read(). + * Has to be declared here as mb_layer1_prototypes.h is included several times! +typedef enum {MB_req_frame, MB_resp_frame, MB_any_frame} mb_frame_type_t; /* Declare TCP layer1 functions */
#define modbus_write modbus_tcp_write
#define modbus_read modbus_tcp_read
--- a/mb_layer1_prototypes.h Sun Oct 16 07:10:20 2022 +0100
+++ b/mb_layer1_prototypes.h Sun Oct 16 14:25:06 2022 +0100
@@ -21,8 +21,6 @@
/* write a modbus frame */
/* WARNING: when calling this function, the *frame_data buffer
* must be allocated with an extra *extra_bytes
@@ -73,6 +71,21 @@
* converters, this functionality is essential as not all these converters
* are capable of not echoing back the sent data.
* These parameters are ignored when using TCP!
+ * requested_frame_type: one of -> MB_req_frame, MB_resp_frame, MB_any_frame + * the type of frame we should search for (request, response, or any) + * NOTE: only used by the RTu layer. Other layers simply ignore this parameter. + * NOTE: whatever the type of frame, searching for error frames is + * always enabled (i.e. this function may always return that it found + * an error frame, whatever frame type it was told to look for) + * This is needed because the RTU protocol may confuse some valid + * response frames with valid query frames (e.g. the response to + * read registers may contain data with values that just so happens + * to match the correct CRC of the read registers query packet, making + * it impossible to distinguish the beginning of a read registers + * response to a read registers query). We only give this priority + * if it is possible to have this con /* RETURNS: number of bytes read
@@ -82,6 +95,7 @@
int modbus_read(int *nd, /* node descriptor */
+ mb_frame_type_t requested_frame_type, const struct timespec *recv_timeout);
--- a/mb_master.c Sun Oct 16 07:10:20 2022 +0100
+++ b/mb_master.c Sun Oct 16 14:25:06 2022 +0100
@@ -221,7 +221,7 @@
* response we are waiting for could be coming 'any minute now'.
- response_length = modbus_read(&ttyfd, response_packet, &recv_transaction_id,
+ response_length = modbus_read(&ttyfd, response_packet, &recv_transaction_id, MB_resp_frame, query_packet, query_length, response_timeout);
@@ -360,9 +360,9 @@
/* handle groups of 4 bytes... */
for(i = 0, dest_pos = 0; i + 3 < byte_count; i += 4, dest_pos++)
- dest[dest_pos] = response_packet[i]
- + response_packet[i+1]*0x100
- + response_packet[i+2]*0x10000
+ dest[dest_pos] = response_packet[i] + + response_packet[i+1]*0x100 + + response_packet[i+2]*0x10000 + response_packet[i+3]*0x1000000;
/* handle any remaining bytes... begining with the last! */
if (i < byte_count) dest[dest_pos] = 0;
--- a/mb_rtu.c Sun Oct 16 07:10:20 2022 +0100
+++ b/mb_rtu.c Sun Oct 16 14:25:06 2022 +0100
@@ -1287,6 +1287,12 @@
/* Search for a valid frame in the current data.
* If no valid frame is found, then we return -1.
+ * requested_frame_type: one of -> MB_req_frame, MB_resp_frame, MB_any_frame (default) + * the type of frame we should search for (request, response, or any) + * NOTE: whatever the type of frame, searching for error frames is always enabled + * (i.e. this function may always return that it found an error frame, + * whatever frame type it was told to look for) * NOTE: Since frame verification is done by calculating the CRC, which is rather
* CPU intensive, and this function may be called several times with the same,
@@ -1295,6 +1301,7 @@
static int search_for_frame(u8 *frame_data,
+ mb_frame_type_t requested_frame_type, int query_length, resp_length;
@@ -1303,6 +1310,17 @@
#define SFF_HIST_NO_RESPONSE_FRAME 0x02
#define SFF_HIST_NO_FRAME (SFF_HIST_NO_RESPONSE_FRAME + SFF_HIST_NO_QUERY_FRAME)
+ if (requested_frame_type == MB_req_frame) + /* only search for request frames => don't search for response frames */ + /* we simply mark the flag indicating not to search for response frames */ + *search_history |= SFF_HIST_NO_RESPONSE_FRAME; + if (requested_frame_type == MB_resp_frame) + /* only search for response frames => don't search for request frames */ + /* we simply mark the flag indicating not to search for request frames */ + *search_history |= SFF_HIST_NO_QUERY_FRAME; if ((*search_history == SFF_HIST_NO_FRAME) ||
(frame_data_length < MIN_FRAME_LENGTH) ||
(frame_data_length > MAX_RTU_FRAME_LENGTH))
@@ -1438,6 +1456,12 @@
/* A function to read a valid frame off the rtu bus.
+ * requested_frame_type: one of -> MB_req_frame, MB_resp_frame, MB_any_frame (default) + * the type of frame we should search for (request, response, or any) + * NOTE: whatever the type of frame, searching for error frames is always enabled + * (i.e. this function may always return that it found an error frame, + * whatever frame type it was told to look for) * - The returned frame is guaranteed to be a valid frame.
* - The returned length does *not* include the CRC.
@@ -1516,7 +1540,9 @@
static inline int read_frame(nd_entry_t *nd_entry,
struct timespec *end_time,
+ mb_frame_type_t requested_frame_type /* temporary variables... */
@@ -1553,6 +1579,7 @@
frame_length = search_for_frame(lb_data(&recv_buf->data_buf),
lb_data_count(&recv_buf->data_buf),
&recv_buf->frame_search_history);
/* We found a valid frame! */
@@ -1625,6 +1652,7 @@
*-----------------------*/
frame_length = search_for_frame(lb_data(&recv_buf->data_buf),
lb_data_count(&recv_buf->data_buf),
&recv_buf->frame_search_history);
/* We found a valid frame! */
@@ -1765,6 +1793,20 @@
* ignore_echo == 0, then the first valid frame read off
+ * requested_frame_type: one of -> MB_req_frame, MB_resp_frame, MB_any_frame (default) + * the type of frame we should search for (request, response, or any) + * NOTE: whatever the type of frame, searching for error frames is + * always enabled (i.e. this function may always return that it found + * an error frame, whatever frame type it was told to look for) + * This is needed because the RTU protocol may confuse some valid + * response frames with valid query frames (e.g. the response to + * read registers may contain data with values that just so happens + * to match the correct CRC of the read registers query packet, making + * it impossible to distinguish the beginning of a read registers + * response to a read registers query). We only give this priority + * if it is possible to have this con * return value: The length (in bytes) of the valid frame,
@@ -1773,6 +1815,7 @@
int modbus_rtu_read(int *nd,
+ mb_frame_type_t requested_frame_type, const struct timespec *recv_timeout) {
@@ -1786,6 +1829,10 @@
+ fprintf(stderr, "modbus_rtu_read(fd=%d) called...\n", *nd); if (recv_data_ptr == NULL)
recv_data_ptr = &local_recv_data_ptr;
@@ -1840,7 +1887,7 @@
- while ((res = recv_length = read_frame(nd_entry, recv_data_ptr, ts_ptr, slave_id)) >= 0) {
+ while ((res = recv_length = read_frame(nd_entry, recv_data_ptr, ts_ptr, slave_id, requested_frame_type)) >= 0) { if (iter < INT_MAX) iter++;
if ((send_length <= 0) || (nd_entry->ignore_echo == 0))
@@ -1853,7 +1900,8 @@
* We must only do this for the first frame we read. Subsequent
* frames are guaranteed not to be the previously sent frame
- * since the modbus_rtu_write() resets the recv buffer.
+ * since the modbus_rtu_write() resets the recv buffer + * (_before_ sending out the message so as to avoid race conditions). * Remember too that valid modbus responses may be exactly the same
--- a/mb_slave.c Sun Oct 16 07:10:20 2022 +0100
+++ b/mb_slave.c Sun Oct 16 14:25:06 2022 +0100
@@ -784,6 +784,7 @@
byte_count = modbus_read(&nd, /* node descriptor */
&query_packet, /* u8 **recv_data_ptr, */
&transaction_id, /* u16 *transaction_id, */
+ MB_req_frame, /* mb_frame_type_t */ NULL, /* const u8 *send_data, */
0, /* int send_length, */
NULL /* wait indefenitely */ /* const struct timespec *recv_timeout); */
--- a/mb_tcp.c Sun Oct 16 07:10:20 2022 +0100
+++ b/mb_tcp.c Sun Oct 16 14:25:06 2022 +0100
@@ -1249,6 +1249,7 @@
int modbus_tcp_read(int *nd, /* node descriptor */
+ mb_frame_type_t requested_frame_type, /* ignored by this layer ! */ const u8 *send_data, /* ignored ! */
int send_length, /* ignored ! */
const struct timespec *recv_timeout) {