Esempio n. 1
0
int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int length_to_read)
{
    int s_rc;
#if defined(_WIN32)
    s_rc = win32_ser_select(&(((modbus_rtu_t*)ctx->backend_data)->w_ser), length_to_read, tv);
    if (s_rc == 0) {
        errno = ETIMEDOUT;
        return -1;
    }

    if (s_rc < 0) {
        _error_print(ctx, "select");
        if (ctx->error_recovery && (errno == EBADF)) {
            modbus_close(ctx);
            modbus_connect(ctx);
            errno = EBADF;
            return -1;
        } else {
            return -1;
        }
    }
#else
    while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) {
        if (errno == EINTR) {
            if (ctx->debug) {
                fprintf(stderr, "A non blocked signal was caught\n");
            }
            /* Necessary after an error */
            FD_ZERO(rfds);
            FD_SET(ctx->s, rfds);
        } else {
            _error_print(ctx, "select");
            if (ctx->error_recovery && (errno == EBADF)) {
                modbus_close(ctx);
                modbus_connect(ctx);
                errno = EBADF;
                return -1;
            } else {
                return -1;
            }
        }
    }

    if (s_rc == 0) {
        /* Timeout */
        errno = ETIMEDOUT;
        _error_print(ctx, "select");
        return -1;
    }
#endif

    return s_rc;
}
Esempio n. 2
0
static int check_confirmation(tta_t *ctx, uint8_t *req,
		uint8_t *buf, int rsp_length)
{
	int rc = 0;

	if (ctx->backend->pre_check_confirmation) {
		rc = ctx->backend->pre_check_confirmation(ctx, req, buf, rsp_length);
		if (rc == -1) {
			if (ctx->error_recovery & TTA_ERROR_RECOVERY_PROTOCOL) {
				_sleep_and_flush(ctx);
			}
			return -1;
		}
	}

#if 0
	/* Exception code */
	if (function >= 0x80) {
		if (rsp_length == (offset + 2 + ctx->backend->checksum_length) &&
				req[offset] == (buf[offset] - 0x80)) {
			/* Valid exception code received */

			int exception_code = buf[offset + 1];
			if (exception_code < TTA_EXCEPTION_MAX) {
				errno = TTA_ENOBASE + exception_code;
			} else {
				errno = EMBBADEXC;
			}
			_error_print(ctx, NULL);
			return -1;
		} else {
			errno = EMBBADEXC;
			_error_print(ctx, NULL);
			return -1;
		}
	}
#endif

	return rc;
}
Esempio n. 3
0
static int _send_pkt(tta_t *ctx, uint8_t *pkt, int pktlen)
{
	int rc, i;

#ifdef DUMP_PKT
#if 0
	if (ctx->debug)
	{
		for (i = 0; i < pktlen; i++)
			LOGD("[%.2X]", pkt[i]);
		LOGD("\n");
	}
#endif
#endif

	/* In recovery mode, the write command will be issued until to be
	   successful! Disabled by default. */
	do {
		rc = ctx->backend->send(ctx, pkt, pktlen);
		if (rc == -1) {
			_error_print(ctx, NULL);
			if (ctx->error_recovery & TTA_ERROR_RECOVERY_LINK) {
				int saved_errno = errno;

				if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) {
					tta_close(ctx);
					tta_connect(ctx);
				} else {
					_sleep_and_flush(ctx);
				}
				errno = saved_errno;
			}
		}
	} while ((ctx->error_recovery & TTA_ERROR_RECOVERY_LINK) &&
			rc == -1);

	if (rc > 0 && rc != pktlen)
	{
		errno = EMBBADDATA;
		return -1;
	}

	return rc;
}
Esempio n. 4
0
/* Sends a request/response */
static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
{
    int rc;
    int i;

    msg_length = ctx->backend->send_msg_pre(msg, msg_length);

    if (ctx->debug) {
        for (i = 0; i < msg_length; i++)
            printf("[%.2X]", msg[i]);
        printf("\n");
    }

    /* In recovery mode, the write command will be issued until to be
       successful! Disabled by default. */
    do {
        rc = ctx->backend->send(ctx, msg, msg_length);
        if (rc == -1) {
            _error_print(ctx, NULL);
            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
                int saved_errno = errno;

                if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) {
                    modbus_close(ctx);
                    modbus_connect(ctx);
                } else {
                    _sleep_and_flush(ctx);
                }
                errno = saved_errno;
            }
        }
    } while ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
             rc == -1);

    if (rc > 0 && rc != msg_length) {
        errno = EMBBADDATA;
        return -1;
    }

    return rc;
}
Esempio n. 5
0
int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length)
{
    int s_rc;
#if defined(_WIN32)
    s_rc = win32_ser_select(&(((modbus_rtu_t*)ctx->backend_data)->w_ser), msg_length_computed, tv);
    if (s_rc == 0) {
        errno = ETIMEDOUT;
        return -1;
    }

    if (s_rc < 0) {
        _error_print(ctx, "select");
        if (ctx->error_recovery && (errno == EBADF)) {
            modbus_close(ctx);
            modbus_connect(ctx);
            errno = EBADF;
            return -1;
        } else {
            return -1;
        }
    }
#else
    while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) {
        if (errno == EINTR) {
            if (ctx->debug) {
                fprintf(stderr, "A non blocked signal was caught\n");
            }
            /* Necessary after an error */
            FD_ZERO(rfds);
            FD_SET(ctx->s, rfds);
        } else {
            _error_print(ctx, "select");
            if (ctx->error_recovery && (errno == EBADF)) {
                modbus_close(ctx);
                modbus_connect(ctx);
                errno = EBADF;
                return -1;
            } else {
                return -1;
            }
        }
    }

    if (s_rc == 0) {
        /* Timeout */
        if (msg_length == (ctx->backend->header_length + 2 +
                           ctx->backend->checksum_length)) {
            /* Optimization allowed because exception response is
               the smallest trame in modbus protocol (3) so always
               raise a timeout error.
               Temporary error before exception analyze. */
            errno = EMBUNKEXC;
        } else {
            errno = ETIMEDOUT;
            _error_print(ctx, "select");
        }
        return -1;
    }
#endif

    return s_rc;
}
Esempio n. 6
0
static int check_confirmation(modbus_t *ctx, uint8_t *req,
                              uint8_t *rsp, int rsp_length)
{
    int rc;
    int rsp_length_computed;
    const int offset = ctx->backend->header_length;
    const int function = rsp[offset];

    if (ctx->backend->pre_check_confirmation) {
        rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length);
        if (rc == -1) {
            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
                _sleep_and_flush(ctx);
            }
            return -1;
        }
    }

    rsp_length_computed = compute_response_length_from_request(ctx, req);

    /* Exception code */
    if (function >= 0x80) {
        if (rsp_length == (offset + 2 + ctx->backend->checksum_length) &&
            req[offset] == (rsp[offset] - 0x80)) {
            /* Valid exception code received */

            int exception_code = rsp[offset + 1];
            if (exception_code < MODBUS_EXCEPTION_MAX) {
                errno = MODBUS_ENOBASE + exception_code;
            } else {
                errno = EMBBADEXC;
            }
            _error_print(ctx, NULL);
            return -1;
        } else {
            errno = EMBBADEXC;
            _error_print(ctx, NULL);
            return -1;
        }
    }

    /* Check length */
    if ((rsp_length == rsp_length_computed ||
         rsp_length_computed == MSG_LENGTH_UNDEFINED) &&
        function < 0x80) {
        int req_nb_value;
        int rsp_nb_value;

        /* Check function code */
        if (function != req[offset]) {
            if (ctx->debug) {
                fprintf(stderr,
                        "Received function not corresponding to the requestd (0x%X != 0x%X)\n",
                        function, req[offset]);
            }
            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
                _sleep_and_flush(ctx);
            }
            errno = EMBBADDATA;
            return -1;
        }

        /* Check the number of values is corresponding to the request */
        switch (function) {
        case _FC_READ_COILS:
        case _FC_READ_DISCRETE_INPUTS:
            /* Read functions, 8 values in a byte (nb
             * of values in the request and byte count in
             * the response. */
            req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
            req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
            rsp_nb_value = rsp[offset + 1];
            break;
        case _FC_WRITE_AND_READ_REGISTERS:
        case _FC_READ_HOLDING_REGISTERS:
        case _FC_READ_INPUT_REGISTERS:
            /* Read functions 1 value = 2 bytes */
            req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
            rsp_nb_value = (rsp[offset + 1] / 2);
            break;
        case _FC_WRITE_MULTIPLE_COILS:
        case _FC_WRITE_MULTIPLE_REGISTERS:
            /* N Write functions */
            req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
            rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4];
            break;
        case _FC_REPORT_SLAVE_ID:
            /* Report slave ID (bytes received) */
            req_nb_value = rsp_nb_value = rsp[offset + 1];
            break;
        default:
            /* 1 Write functions & others */
            req_nb_value = rsp_nb_value = 1;
        }

        if (req_nb_value == rsp_nb_value) {
            rc = rsp_nb_value;
        } else {
            if (ctx->debug) {
                fprintf(stderr,
                        "Quantity not corresponding to the request (%d != %d)\n",
                        rsp_nb_value, req_nb_value);
            }

            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
                _sleep_and_flush(ctx);
            }

            errno = EMBBADDATA;
            rc = -1;
        }
    } else {
        if (ctx->debug) {
            fprintf(stderr,
                    "Message length not corresponding to the computed length (%d != %d)\n",
                    rsp_length, rsp_length_computed);
        }
        if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
            _sleep_and_flush(ctx);
        }
        errno = EMBBADDATA;
        rc = -1;
    }

    return rc;
}
Esempio n. 7
0
int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
{
    int rc;
    fd_set rset;
    struct timeval tv;
    struct timeval *p_tv;
    int length_to_read;
    int msg_length = 0;
    _step_t step;

    if (ctx->debug) {
        if (msg_type == MSG_INDICATION) {
            printf("Waiting for a indication...\n");
        } else {
            printf("Waiting for a confirmation...\n");
        }
    }

    /* Add a file descriptor to the set */
    FD_ZERO(&rset);
    FD_SET(ctx->s, &rset);

    /* We need to analyse the message step by step.  At the first step, we want
     * to reach the function code because all packets contain this
     * information. */
    step = _STEP_FUNCTION;
    length_to_read = ctx->backend->header_length + 1;

    if (msg_type == MSG_INDICATION) {
        /* Wait for a message, we don't know when the message will be
         * received */
        p_tv = NULL;
    } else {
        tv.tv_sec = ctx->response_timeout.tv_sec;
        tv.tv_usec = ctx->response_timeout.tv_usec;
        p_tv = &tv;
    }

    while (length_to_read != 0) {
        rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);
        if (rc == -1) {
            _error_print(ctx, "select");
            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
                int saved_errno = errno;

                if (errno == ETIMEDOUT) {
                    _sleep_and_flush(ctx);
                } else if (errno == EBADF) {
                    modbus_close(ctx);
                    modbus_connect(ctx);
                }
                errno = saved_errno;
            }
            return -1;
        }

        rc = ctx->backend->recv(ctx, msg + msg_length, length_to_read);
        if (rc == 0) {
            errno = ECONNRESET;
            rc = -1;
        }

        if (rc == -1) {
            _error_print(ctx, "read");
            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
                (errno == ECONNRESET || errno == ECONNREFUSED ||
                 errno == EBADF)) {
                int saved_errno = errno;
                modbus_close(ctx);
                modbus_connect(ctx);
                /* Could be removed by previous calls */
                errno = saved_errno;
            }
            return -1;
        }

        /* Display the hex code of each character received */
        if (ctx->debug) {
            int i;
            for (i=0; i < rc; i++)
                printf("<%.2X>", msg[msg_length + i]);
        }

        /* Sums bytes received */
        msg_length += rc;
        /* Computes remaining bytes */
        length_to_read -= rc;

        if (length_to_read == 0) {
            switch (step) {
            case _STEP_FUNCTION:
                /* Function code position */
                length_to_read = compute_meta_length_after_function(
                    msg[ctx->backend->header_length],
                    msg_type);
                if (length_to_read != 0) {
                    step = _STEP_META;
                    break;
                } /* else switches straight to the next step */
            case _STEP_META:
                length_to_read = compute_data_length_after_meta(
                    ctx, msg, msg_type);
                if ((msg_length + length_to_read) > ctx->backend->max_adu_length) {
                    errno = EMBBADDATA;
                    _error_print(ctx, "too many data");
                    return -1;
                }
                step = _STEP_DATA;
                break;
            default:
                break;
            }
        }

        if (length_to_read > 0 && ctx->byte_timeout.tv_sec != -1) {
            /* If there is no character in the buffer, the allowed timeout
               interval between two consecutive bytes is defined by
               byte_timeout */
            tv.tv_sec = ctx->byte_timeout.tv_sec;
            tv.tv_usec = ctx->byte_timeout.tv_usec;
            p_tv = &tv;
        }
    }

    if (ctx->debug)
        printf("\n");

    return ctx->backend->check_integrity(ctx, msg, msg_length);
}
Esempio n. 8
0
/* Waits a response from a tta server or a request from a tta client.
   This function blocks if there is no replies (3 timeouts).

   The function shall return the number of received characters and the received
   message in an array of uint8_t if successful. Otherwise it shall return -1
   and errno is set to one of the values defined below:
   - ECONNRESET
   - EMBBADDATA
   - EMBUNKEXC
   - ETIMEDOUT
   - read() or recv() error codes
   */
int _tta_receive_pkt(tta_t *ctx, uint8_t *pkt, int fgtimeout)
{
	fd_set rfds;
	struct timeval tv;
	struct timeval *p_tv;
	int length_to_read;
	int pktlen = 0;
	_step_t step;
	int rc;

	if (ctx->debug) {
		if (fgtimeout) {
			LOGD("Waiting until timeout...\n");
		} else {
			LOGD("Waiting without timeout...\n");
		}
	}

	/* Add a file descriptor to the set */
	FD_ZERO(&rfds);
	FD_SET(ctx->s, &rfds);

	step = _STEP_HD;
	length_to_read = ctx->backend->header_length;

	if (fgtimeout) {
		tv.tv_sec = ctx->response_timeout.tv_sec;
		tv.tv_usec = ctx->response_timeout.tv_usec;
		p_tv = &tv;
	} else {
		/* Wait for a message, we don't know when the message will be
		 * received */
		p_tv = NULL;
	}

	while (length_to_read != 0)
	{
		rc = ctx->backend->select(ctx, &rfds, p_tv, length_to_read);
		if (rc == -1)
		{
			_error_print(ctx, "select");
			if (ctx->error_recovery & TTA_ERROR_RECOVERY_LINK)
			{
				int saved_errno = errno;

				if (errno == ETIMEDOUT)
				{
					_sleep_and_flush(ctx);
				}
				else if (errno == EBADF)
				{
					tta_close(ctx);
					tta_connect(ctx);
				}
				errno = saved_errno;
			}
			return -1;
		}

		rc = ctx->backend->recv(ctx, pkt+pktlen, length_to_read);
		if (rc == 0)
		{
			errno = ECONNRESET;
			rc = -1;
		}

		if (rc == -1)
		{
			_error_print(ctx, "read");
			if ((ctx->error_recovery & TTA_ERROR_RECOVERY_LINK) &&
					(errno == ECONNRESET || errno == ECONNREFUSED ||
					 errno == EBADF))
			{
				int saved_errno = errno;

				tta_close(ctx);
				tta_connect(ctx);
				/* Could be removed by previous calls */
				errno = saved_errno;
			}
			return -1;
		}

		/* Display the hex code of each character received */
#ifdef DUMP_PKT
#if 0
		if (ctx->debug)
		{
			int i;
			for (i=0; i < rc; i++)
				LOGD("<%.2X>", pkt[pktlen + i]);
		}
#endif
#endif

		/* Sums bytes received */
		pktlen += rc;
		/* Computes remaining bytes */
		length_to_read -= rc;

		if (length_to_read == 0)
		{
			switch (step)
			{
				case _STEP_HD:
					/* Function code position */
					length_to_read = compute_data_length_after_hd(ctx, pkt);
					if((pktlen+length_to_read) > ctx->backend->max_adu_length)
					{
						errno = EMBBADDATA;
						_error_print(ctx, "too many data");
						return -1;
					}
					step = _STEP_DATA;
					break;
				case _STEP_DATA:
				case _STEP_TAIL:
				default:
					break;
			}
		}

		if (length_to_read > 0)
		{
			/* If there is no character in the buffer, the allowed timeout
			   interval between two consecutive bytes is defined by
			   byte_timeout */
			tv.tv_sec = ctx->byte_timeout.tv_sec;
			tv.tv_usec = ctx->byte_timeout.tv_usec;
			p_tv = &tv;
		}
	}

	/* Display the hex code of each character received */
	if (ctx->debug)
		LOGD("\n");

	return ctx->backend->check_integrity(ctx, pkt, pktlen);
}