modbus: rework interface configuration
Use commot parameter structure to configure server or client interfaces. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
parent
55204d504e
commit
4ff616b647
8 changed files with 338 additions and 204 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 PHYTEC Messtechnik GmbH
|
* Copyright (c) 2020 PHYTEC Messtechnik GmbH
|
||||||
|
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -347,44 +348,79 @@ struct modbus_user_callbacks {
|
||||||
int modbus_iface_get_by_name(const char *iface_name);
|
int modbus_iface_get_by_name(const char *iface_name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Configure Modbus Interface as server
|
* @brief Modbus interface mode
|
||||||
*
|
|
||||||
* @param iface Modbus interface index
|
|
||||||
* @param unit_id Modbus unit ID of the server
|
|
||||||
* @param baud Baudrate of the serial line
|
|
||||||
* @param parity UART's parity setting:
|
|
||||||
* UART_CFG_PARITY_NONE,
|
|
||||||
* UART_CFG_PARITY_EVEN,
|
|
||||||
* UART_CFG_PARITY_ODD
|
|
||||||
* @param cb Pointer to the User Callback structure
|
|
||||||
* @param ascii_mode Enable ASCII Transfer Mode
|
|
||||||
*
|
|
||||||
* @retval 0 If the function was successful
|
|
||||||
*/
|
*/
|
||||||
int modbus_init_server(const uint8_t iface, const uint8_t unit_id,
|
enum modbus_mode {
|
||||||
const uint32_t baud, enum uart_config_parity parity,
|
/** Modbus over serial line RTU mode */
|
||||||
struct modbus_user_callbacks *const cb,
|
MODBUS_MODE_RTU,
|
||||||
bool ascii_mode);
|
/** Modbus over serial line ASCII mode */
|
||||||
|
MODBUS_MODE_ASCII,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Configure Modbus Interface as client
|
* @brief Modbus serial line parameter
|
||||||
|
*/
|
||||||
|
struct modbus_serial_param {
|
||||||
|
/** Baudrate of the serial line */
|
||||||
|
uint32_t baud;
|
||||||
|
/** parity UART's parity setting:
|
||||||
|
* UART_CFG_PARITY_NONE,
|
||||||
|
* UART_CFG_PARITY_EVEN,
|
||||||
|
* UART_CFG_PARITY_ODD
|
||||||
|
*/
|
||||||
|
enum uart_config_parity parity;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modbus server parameter
|
||||||
|
*/
|
||||||
|
struct modbus_server_param {
|
||||||
|
/** Pointer to the User Callback structure */
|
||||||
|
struct modbus_user_callbacks *user_cb;
|
||||||
|
/** Modbus unit ID of the server */
|
||||||
|
uint8_t unit_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief User parameter structure to configure Modbus interfase
|
||||||
|
* as client or server.
|
||||||
|
*/
|
||||||
|
struct modbus_iface_param {
|
||||||
|
/** Mode of the interface */
|
||||||
|
enum modbus_mode mode;
|
||||||
|
union {
|
||||||
|
struct modbus_server_param server;
|
||||||
|
/** Amount of time client will wait for
|
||||||
|
* a response from the server.
|
||||||
|
*/
|
||||||
|
uint32_t rx_timeout;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
/** Serial support parameter of the interface */
|
||||||
|
struct modbus_serial_param serial;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure Modbus Interface as raw ADU server
|
||||||
*
|
*
|
||||||
* @param iface Modbus interface index
|
* @param iface Modbus RTU interface index
|
||||||
* @param baud Baudrate of the serial line
|
* @param param Configuration parameter of the server interface
|
||||||
* @param parity UART's parity setting:
|
|
||||||
* UART_CFG_PARITY_NONE,
|
|
||||||
* UART_CFG_PARITY_EVEN,
|
|
||||||
* UART_CFG_PARITY_ODD
|
|
||||||
* @param rx_timeout Amount of time client will wait for a response
|
|
||||||
* from the server.
|
|
||||||
* @param ascii_mode Enable ASCII Transfer Mode
|
|
||||||
*
|
*
|
||||||
* @retval 0 If the function was successful
|
* @retval 0 If the function was successful
|
||||||
*/
|
*/
|
||||||
int modbus_init_client(const uint8_t iface,
|
int modbus_init_server(const int iface, struct modbus_iface_param param);
|
||||||
const uint32_t baud, enum uart_config_parity parity,
|
|
||||||
uint32_t rx_timeout,
|
/**
|
||||||
bool ascii_mode);
|
* @brief Configure Modbus Interface as raw ADU client
|
||||||
|
*
|
||||||
|
* @param iface Modbus RTU interface index
|
||||||
|
* @param param Configuration parameter of the client interface
|
||||||
|
*
|
||||||
|
* @retval 0 If the function was successful
|
||||||
|
*/
|
||||||
|
int modbus_init_client(const int iface, struct modbus_iface_param param);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Disable Modbus Interface
|
* @brief Disable Modbus Interface
|
||||||
*
|
*
|
||||||
|
|
|
@ -12,15 +12,24 @@
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
LOG_MODULE_REGISTER(mbc_sample, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(mbc_sample, LOG_LEVEL_INF);
|
||||||
|
|
||||||
#define RTU_IFACE 0
|
static int client_iface;
|
||||||
|
|
||||||
|
const static struct modbus_iface_param client_param = {
|
||||||
|
.mode = MODBUS_MODE_RTU,
|
||||||
|
.rx_timeout = 50000,
|
||||||
|
.serial = {
|
||||||
|
.baud = 19200,
|
||||||
|
.parity = UART_CFG_PARITY_NONE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static int init_modbus_client(void)
|
static int init_modbus_client(void)
|
||||||
{
|
{
|
||||||
const uint32_t mb_rtu_br = 19200;
|
const char iface_name[] = {DT_PROP(DT_INST(0, zephyr_modbus_serial), label)};
|
||||||
const uint32_t rsp_timeout = 50000;
|
|
||||||
|
|
||||||
return modbus_init_client(RTU_IFACE, mb_rtu_br, UART_CFG_PARITY_NONE,
|
client_iface = modbus_iface_get_by_name(iface_name);
|
||||||
rsp_timeout, false);
|
|
||||||
|
return modbus_init_client(client_iface, client_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
|
@ -38,14 +47,14 @@ void main(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = modbus_write_holding_regs(RTU_IFACE, node, 0, holding_reg,
|
err = modbus_write_holding_regs(client_iface, node, 0, holding_reg,
|
||||||
ARRAY_SIZE(holding_reg));
|
ARRAY_SIZE(holding_reg));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC16 failed");
|
LOG_ERR("FC16 failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = modbus_read_holding_regs(RTU_IFACE, node, 0, holding_reg,
|
err = modbus_read_holding_regs(client_iface, node, 0, holding_reg,
|
||||||
ARRAY_SIZE(holding_reg));
|
ARRAY_SIZE(holding_reg));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC03 failed with %d", err);
|
LOG_ERR("FC03 failed with %d", err);
|
||||||
|
@ -58,7 +67,7 @@ void main(void)
|
||||||
while (true) {
|
while (true) {
|
||||||
uint16_t addr = 0;
|
uint16_t addr = 0;
|
||||||
|
|
||||||
err = modbus_read_coils(RTU_IFACE, node, 0, coil, coil_qty);
|
err = modbus_read_coils(client_iface, node, 0, coil, coil_qty);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC01 failed with %d", err);
|
LOG_ERR("FC01 failed with %d", err);
|
||||||
return;
|
return;
|
||||||
|
@ -66,28 +75,28 @@ void main(void)
|
||||||
|
|
||||||
LOG_INF("Coils state 0x%02x", coil[0]);
|
LOG_INF("Coils state 0x%02x", coil[0]);
|
||||||
|
|
||||||
err = modbus_write_coil(RTU_IFACE, node, addr++, true);
|
err = modbus_write_coil(client_iface, node, addr++, true);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC05 failed with %d", err);
|
LOG_ERR("FC05 failed with %d", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_msleep(sleep);
|
k_msleep(sleep);
|
||||||
err = modbus_write_coil(RTU_IFACE, node, addr++, true);
|
err = modbus_write_coil(client_iface, node, addr++, true);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC05 failed with %d", err);
|
LOG_ERR("FC05 failed with %d", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_msleep(sleep);
|
k_msleep(sleep);
|
||||||
err = modbus_write_coil(RTU_IFACE, node, addr++, true);
|
err = modbus_write_coil(client_iface, node, addr++, true);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC05 failed with %d", err);
|
LOG_ERR("FC05 failed with %d", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
k_msleep(sleep);
|
k_msleep(sleep);
|
||||||
err = modbus_read_coils(RTU_IFACE, node, 0, coil, coil_qty);
|
err = modbus_read_coils(client_iface, node, 0, coil, coil_qty);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC01 failed with %d", err);
|
LOG_ERR("FC01 failed with %d", err);
|
||||||
return;
|
return;
|
||||||
|
@ -96,7 +105,7 @@ void main(void)
|
||||||
LOG_INF("Coils state 0x%02x", coil[0]);
|
LOG_INF("Coils state 0x%02x", coil[0]);
|
||||||
|
|
||||||
coil[0] = 0;
|
coil[0] = 0;
|
||||||
err = modbus_write_coils(RTU_IFACE, node, 0, coil, coil_qty);
|
err = modbus_write_coils(client_iface, node, 0, coil, coil_qty);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
LOG_ERR("FC15 failed with %d", err);
|
LOG_ERR("FC15 failed with %d", err);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -100,6 +100,18 @@ static struct modbus_user_callbacks mbs_cbs = {
|
||||||
.holding_reg_wr = holding_reg_wr,
|
.holding_reg_wr = holding_reg_wr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const static struct modbus_iface_param server_param = {
|
||||||
|
.mode = MODBUS_MODE_RTU,
|
||||||
|
.server = {
|
||||||
|
.user_cb = &mbs_cbs,
|
||||||
|
.unit_id = 1,
|
||||||
|
},
|
||||||
|
.serial = {
|
||||||
|
.baud = 19200,
|
||||||
|
.parity = UART_CFG_PARITY_NONE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static int init_modbus_server(void)
|
static int init_modbus_server(void)
|
||||||
{
|
{
|
||||||
const uint32_t mb_rtu_br = 19200;
|
const uint32_t mb_rtu_br = 19200;
|
||||||
|
@ -113,8 +125,7 @@ static int init_modbus_server(void)
|
||||||
return iface;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
return modbus_init_server(iface, 1, mb_rtu_br, UART_CFG_PARITY_NONE,
|
return modbus_init_server(iface, server_param);
|
||||||
&mbs_cbs, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
|
|
|
@ -149,13 +149,18 @@ struct modbus_context *modbus_get_context(const uint8_t iface)
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct modbus_context *mb_cfg_iface(const uint8_t iface,
|
int modbus_iface_get_by_name(const char *iface_name)
|
||||||
const uint8_t unit_id,
|
{
|
||||||
const uint32_t baud,
|
for (int i = 0; i < ARRAY_SIZE(mb_ctx_tbl); i++) {
|
||||||
const enum uart_config_parity parity,
|
if (strcmp(iface_name, mb_ctx_tbl[i].iface_name) == 0) {
|
||||||
const uint32_t rx_timeout,
|
return i;
|
||||||
const bool client,
|
}
|
||||||
const bool ascii_mode)
|
}
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct modbus_context *modbus_init_iface(const uint8_t iface)
|
||||||
{
|
{
|
||||||
struct modbus_context *ctx;
|
struct modbus_context *ctx;
|
||||||
|
|
||||||
|
@ -171,118 +176,129 @@ static struct modbus_context *mb_cfg_iface(const uint8_t iface,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((client == true) &&
|
|
||||||
!IS_ENABLED(CONFIG_MODBUS_CLIENT)) {
|
|
||||||
LOG_ERR("Modbus client support is not enabled");
|
|
||||||
ctx->client = false;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->rxwait_to = rx_timeout;
|
|
||||||
ctx->unit_id = unit_id;
|
|
||||||
ctx->client = client;
|
|
||||||
ctx->mbs_user_cb = NULL;
|
|
||||||
k_mutex_init(&ctx->iface_lock);
|
k_mutex_init(&ctx->iface_lock);
|
||||||
|
|
||||||
k_sem_init(&ctx->client_wait_sem, 0, 1);
|
k_sem_init(&ctx->client_wait_sem, 0, 1);
|
||||||
k_work_init(&ctx->server_work, modbus_rx_handler);
|
k_work_init(&ctx->server_work, modbus_rx_handler);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_MODBUS_FC08_DIAGNOSTIC)) {
|
|
||||||
modbus_reset_stats(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ctx->mode) {
|
|
||||||
case MODBUS_MODE_RTU:
|
|
||||||
case MODBUS_MODE_ASCII:
|
|
||||||
if (IS_ENABLED(CONFIG_MODBUS_SERIAL) &&
|
|
||||||
modbus_serial_init(ctx, baud, parity, ascii_mode) != 0) {
|
|
||||||
LOG_ERR("Failed to init MODBUS over serial line");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERR("Unknown MODBUS mode");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("Modbus interface %s initialized", ctx->iface_name);
|
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int modbus_init_server(const uint8_t iface, const uint8_t unit_id,
|
int modbus_init_server(const int iface, struct modbus_iface_param param)
|
||||||
const uint32_t baud, const enum uart_config_parity parity,
|
|
||||||
struct modbus_user_callbacks *const cb,
|
|
||||||
const bool ascii_mode)
|
|
||||||
{
|
{
|
||||||
struct modbus_context *ctx;
|
struct modbus_context *ctx = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
if (!IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
||||||
LOG_ERR("Modbus server support is not enabled");
|
LOG_ERR("Modbus server support is not enabled");
|
||||||
return -ENOTSUP;
|
rc = -ENOTSUP;
|
||||||
|
goto init_server_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb == NULL) {
|
if (param.server.user_cb == NULL) {
|
||||||
LOG_ERR("User callbacks should be available");
|
LOG_ERR("User callbacks should be available");
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto init_server_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = mb_cfg_iface(iface, unit_id, baud,
|
ctx = modbus_init_iface(iface);
|
||||||
parity, 0, false, ascii_mode);
|
|
||||||
|
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto init_server_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->mbs_user_cb = cb;
|
switch (param.mode) {
|
||||||
|
case MODBUS_MODE_RTU:
|
||||||
|
case MODBUS_MODE_ASCII:
|
||||||
|
if (IS_ENABLED(CONFIG_MODBUS_SERIAL) &&
|
||||||
|
modbus_serial_init(ctx, param) != 0) {
|
||||||
|
LOG_ERR("Failed to init MODBUS over serial line");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto init_server_error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERR("Unknown MODBUS mode");
|
||||||
|
rc = -ENOTSUP;
|
||||||
|
goto init_server_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->client = false;
|
||||||
|
ctx->unit_id = param.server.unit_id;
|
||||||
|
ctx->mbs_user_cb = param.server.user_cb;
|
||||||
|
if (IS_ENABLED(CONFIG_MODBUS_FC08_DIAGNOSTIC)) {
|
||||||
|
modbus_reset_stats(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Modbus interface %s initialized", ctx->iface_name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
int modbus_iface_get_by_name(const char *iface_name)
|
init_server_error:
|
||||||
{
|
if (ctx != NULL) {
|
||||||
for (int i = 0; i < ARRAY_SIZE(mb_ctx_tbl); i++) {
|
atomic_clear_bit(&ctx->state, MODBUS_STATE_CONFIGURED);
|
||||||
if (strcmp(iface_name, mb_ctx_tbl[i].iface_name) == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENODEV;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int modbus_init_client(const uint8_t iface,
|
int modbus_init_client(const int iface, struct modbus_iface_param param)
|
||||||
const uint32_t baud, const enum uart_config_parity parity,
|
|
||||||
const uint32_t rx_timeout,
|
|
||||||
const bool ascii_mode)
|
|
||||||
{
|
{
|
||||||
struct modbus_context *ctx;
|
struct modbus_context *ctx = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_MODBUS_CLIENT)) {
|
if (!IS_ENABLED(CONFIG_MODBUS_CLIENT)) {
|
||||||
LOG_ERR("Modbus client support is not enabled");
|
LOG_ERR("Modbus client support is not enabled");
|
||||||
return -ENOTSUP;
|
rc = -ENOTSUP;
|
||||||
|
goto init_client_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = mb_cfg_iface(iface, 0, baud,
|
ctx = modbus_init_iface(iface);
|
||||||
parity, rx_timeout, true, ascii_mode);
|
|
||||||
|
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto init_client_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (param.mode) {
|
||||||
|
case MODBUS_MODE_RTU:
|
||||||
|
case MODBUS_MODE_ASCII:
|
||||||
|
if (IS_ENABLED(CONFIG_MODBUS_SERIAL) &&
|
||||||
|
modbus_serial_init(ctx, param) != 0) {
|
||||||
|
LOG_ERR("Failed to init MODBUS over serial line");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto init_client_error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERR("Unknown MODBUS mode");
|
||||||
|
rc = -ENOTSUP;
|
||||||
|
goto init_client_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->client = true;
|
||||||
|
ctx->unit_id = 0;
|
||||||
|
ctx->mbs_user_cb = NULL;
|
||||||
|
ctx->rxwait_to = param.rx_timeout;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
init_client_error:
|
||||||
|
if (ctx != NULL) {
|
||||||
|
atomic_clear_bit(&ctx->state, MODBUS_STATE_CONFIGURED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int modbus_disable(const uint8_t iface)
|
int modbus_disable(const uint8_t iface)
|
||||||
{
|
{
|
||||||
struct modbus_context *ctx;
|
struct modbus_context *ctx;
|
||||||
|
|
||||||
if (iface >= ARRAY_SIZE(mb_ctx_tbl)) {
|
ctx = modbus_get_context(iface);
|
||||||
LOG_ERR("Interface %u not available", iface);
|
if (ctx == NULL) {
|
||||||
|
LOG_ERR("Interface %u not initialized", iface);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = &mb_ctx_tbl[iface];
|
|
||||||
|
|
||||||
switch (ctx->mode) {
|
switch (ctx->mode) {
|
||||||
case MODBUS_MODE_RTU:
|
case MODBUS_MODE_RTU:
|
||||||
case MODBUS_MODE_ASCII:
|
case MODBUS_MODE_ASCII:
|
||||||
|
@ -300,7 +316,7 @@ int modbus_disable(const uint8_t iface)
|
||||||
ctx->mbs_user_cb = NULL;
|
ctx->mbs_user_cb = NULL;
|
||||||
atomic_clear_bit(&ctx->state, MODBUS_STATE_CONFIGURED);
|
atomic_clear_bit(&ctx->state, MODBUS_STATE_CONFIGURED);
|
||||||
|
|
||||||
LOG_INF("Disable Modbus interface");
|
LOG_INF("Modbus interface %u disabled", iface);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,11 +87,6 @@ struct mb_rtu_gpio_config {
|
||||||
gpio_dt_flags_t flags;
|
gpio_dt_flags_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum modbus_mode {
|
|
||||||
MODBUS_MODE_RTU,
|
|
||||||
MODBUS_MODE_ASCII,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct modbus_serial_config {
|
struct modbus_serial_config {
|
||||||
/* UART device name */
|
/* UART device name */
|
||||||
const char *dev_name;
|
const char *dev_name;
|
||||||
|
@ -244,19 +239,12 @@ int modbus_serial_tx_adu(struct modbus_context *ctx);
|
||||||
* @brief Initialize serial line support.
|
* @brief Initialize serial line support.
|
||||||
*
|
*
|
||||||
* @param ctx Modbus interface context
|
* @param ctx Modbus interface context
|
||||||
* @param baudrate Baudrate of the serial line
|
* @param param Configuration parameter of the interface
|
||||||
* @param parity UART's parity setting:
|
|
||||||
* UART_CFG_PARITY_NONE,
|
|
||||||
* UART_CFG_PARITY_EVEN,
|
|
||||||
* UART_CFG_PARITY_ODD
|
|
||||||
* @param ascii_mode Enable ASCII Transfer Mode
|
|
||||||
*
|
*
|
||||||
* @retval 0 If the function was successful.
|
* @retval 0 If the function was successful.
|
||||||
*/
|
*/
|
||||||
int modbus_serial_init(struct modbus_context *ctx,
|
int modbus_serial_init(struct modbus_context *ctx,
|
||||||
uint32_t baudrate,
|
struct modbus_iface_param param);
|
||||||
enum uart_config_parity parity,
|
|
||||||
const bool ascii_mode);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Disable serial line support.
|
* @brief Disable serial line support.
|
||||||
|
|
|
@ -526,15 +526,22 @@ int modbus_serial_tx_adu(struct modbus_context *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
int modbus_serial_init(struct modbus_context *ctx,
|
int modbus_serial_init(struct modbus_context *ctx,
|
||||||
uint32_t baudrate,
|
struct modbus_iface_param param)
|
||||||
enum uart_config_parity parity,
|
|
||||||
const bool ascii_mode)
|
|
||||||
{
|
{
|
||||||
struct modbus_serial_config *cfg = ctx->cfg;
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
const uint32_t if_delay_max = 3500000;
|
const uint32_t if_delay_max = 3500000;
|
||||||
const uint32_t numof_bits = 11;
|
const uint32_t numof_bits = 11;
|
||||||
struct uart_config uart_cfg;
|
struct uart_config uart_cfg;
|
||||||
|
|
||||||
|
switch (param.mode) {
|
||||||
|
case MODBUS_MODE_RTU:
|
||||||
|
case MODBUS_MODE_ASCII:
|
||||||
|
ctx->mode = param.mode;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
cfg->dev = device_get_binding(cfg->dev_name);
|
cfg->dev = device_get_binding(cfg->dev_name);
|
||||||
if (cfg->dev == NULL) {
|
if (cfg->dev == NULL) {
|
||||||
LOG_ERR("Failed to get UART device %s",
|
LOG_ERR("Failed to get UART device %s",
|
||||||
|
@ -542,7 +549,7 @@ int modbus_serial_init(struct modbus_context *ctx,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_cfg.baudrate = baudrate,
|
uart_cfg.baudrate = param.serial.baud,
|
||||||
uart_cfg.flow_ctrl = UART_CFG_FLOW_CTRL_NONE;
|
uart_cfg.flow_ctrl = UART_CFG_FLOW_CTRL_NONE;
|
||||||
|
|
||||||
if (ctx->mode == MODBUS_MODE_ASCII) {
|
if (ctx->mode == MODBUS_MODE_ASCII) {
|
||||||
|
@ -551,15 +558,15 @@ int modbus_serial_init(struct modbus_context *ctx,
|
||||||
uart_cfg.data_bits = UART_CFG_DATA_BITS_8;
|
uart_cfg.data_bits = UART_CFG_DATA_BITS_8;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (parity) {
|
switch (param.serial.parity) {
|
||||||
case UART_CFG_PARITY_ODD:
|
case UART_CFG_PARITY_ODD:
|
||||||
case UART_CFG_PARITY_EVEN:
|
case UART_CFG_PARITY_EVEN:
|
||||||
uart_cfg.parity = parity;
|
uart_cfg.parity = param.serial.parity;
|
||||||
uart_cfg.stop_bits = UART_CFG_STOP_BITS_1;
|
uart_cfg.stop_bits = UART_CFG_STOP_BITS_1;
|
||||||
break;
|
break;
|
||||||
case UART_CFG_PARITY_NONE:
|
case UART_CFG_PARITY_NONE:
|
||||||
/* Use of no parity requires 2 stop bits */
|
/* Use of no parity requires 2 stop bits */
|
||||||
uart_cfg.parity = parity;
|
uart_cfg.parity = param.serial.parity;
|
||||||
uart_cfg.stop_bits = UART_CFG_STOP_BITS_2;
|
uart_cfg.stop_bits = UART_CFG_STOP_BITS_2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -571,8 +578,9 @@ int modbus_serial_init(struct modbus_context *ctx,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baudrate <= 38400) {
|
if (param.serial.baud <= 38400) {
|
||||||
cfg->rtu_timeout = (numof_bits * if_delay_max) / baudrate;
|
cfg->rtu_timeout = (numof_bits * if_delay_max) /
|
||||||
|
param.serial.baud;
|
||||||
} else {
|
} else {
|
||||||
cfg->rtu_timeout = (numof_bits * if_delay_max) / 38400;
|
cfg->rtu_timeout = (numof_bits * if_delay_max) / 38400;
|
||||||
}
|
}
|
||||||
|
@ -583,12 +591,12 @@ int modbus_serial_init(struct modbus_context *ctx,
|
||||||
|
|
||||||
cfg->uart_buf_ctr = 0;
|
cfg->uart_buf_ctr = 0;
|
||||||
cfg->uart_buf_ptr = &cfg->uart_buf[0];
|
cfg->uart_buf_ptr = &cfg->uart_buf[0];
|
||||||
uart_irq_callback_user_data_set(cfg->dev, uart_cb_handler, ctx);
|
|
||||||
modbus_serial_rx_on(ctx);
|
|
||||||
|
|
||||||
ctx->mode = ascii_mode ? MODBUS_MODE_ASCII : MODBUS_MODE_RTU;
|
uart_irq_callback_user_data_set(cfg->dev, uart_cb_handler, ctx);
|
||||||
k_timer_init(&cfg->rtu_timer, rtu_tmr_handler, NULL);
|
k_timer_init(&cfg->rtu_timer, rtu_tmr_handler, NULL);
|
||||||
k_timer_user_data_set(&cfg->rtu_timer, ctx);
|
k_timer_user_data_set(&cfg->rtu_timer, ctx);
|
||||||
|
|
||||||
|
modbus_serial_rx_on(ctx);
|
||||||
LOG_INF("RTU timeout %u us", cfg->rtu_timeout);
|
LOG_INF("RTU timeout %u us", cfg->rtu_timeout);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -11,11 +11,12 @@ LOG_MODULE_REGISTER(mbc_test, LOG_LEVEL_INF);
|
||||||
|
|
||||||
#ifdef CONFIG_MODBUS_CLIENT
|
#ifdef CONFIG_MODBUS_CLIENT
|
||||||
const static uint16_t fp_offset = MB_TEST_FP_OFFSET;
|
const static uint16_t fp_offset = MB_TEST_FP_OFFSET;
|
||||||
const static uint8_t iface = MB_TEST_IFACE_CLIENT;
|
|
||||||
const static uint8_t node = MB_TEST_NODE_ADDR;
|
const static uint8_t node = MB_TEST_NODE_ADDR;
|
||||||
const static uint16_t offset_oor = 32;
|
const static uint16_t offset_oor = 32;
|
||||||
const static uint16_t fp_offset_oor = fp_offset + offset_oor;
|
const static uint16_t fp_offset_oor = fp_offset + offset_oor;
|
||||||
|
|
||||||
|
static uint8_t client_iface;
|
||||||
|
|
||||||
void test_coil_wr_rd(void)
|
void test_coil_wr_rd(void)
|
||||||
{
|
{
|
||||||
const uint8_t coil_qty = 16;
|
const uint8_t coil_qty = 16;
|
||||||
|
@ -23,35 +24,35 @@ void test_coil_wr_rd(void)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (uint16_t idx = 0; idx < coil_qty; idx++) {
|
for (uint16_t idx = 0; idx < coil_qty; idx++) {
|
||||||
err = modbus_write_coil(iface, node, idx, true);
|
err = modbus_write_coil(client_iface, node, idx, true);
|
||||||
zassert_equal(err, 0, "FC05 request failed");
|
zassert_equal(err, 0, "FC05 request failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
err = modbus_read_coils(iface, node, 0, coil, coil_qty);
|
err = modbus_read_coils(client_iface, node, 0, coil, coil_qty);
|
||||||
zassert_equal(err, 0, "FC01 request failed");
|
zassert_equal(err, 0, "FC01 request failed");
|
||||||
|
|
||||||
zassert_equal(coil[0], 0xff, "FC05 verify coil 0-7 failed");
|
zassert_equal(coil[0], 0xff, "FC05 verify coil 0-7 failed");
|
||||||
zassert_equal(coil[1], 0xff, "FC05 verify coil 8-15 failed");
|
zassert_equal(coil[1], 0xff, "FC05 verify coil 8-15 failed");
|
||||||
|
|
||||||
for (uint16_t numof = 1; numof <= coil_qty; numof++) {
|
for (uint16_t numof = 1; numof <= coil_qty; numof++) {
|
||||||
err = modbus_write_coils(iface, node, 0, coil, numof);
|
err = modbus_write_coils(client_iface, node, 0, coil, numof);
|
||||||
zassert_equal(err, 0, "FC15 request failed");
|
zassert_equal(err, 0, "FC15 request failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
coil[0] = 0xaa; coil[1] = 0xbb;
|
coil[0] = 0xaa; coil[1] = 0xbb;
|
||||||
err = modbus_write_coils(iface, node, 0, coil, coil_qty);
|
err = modbus_write_coils(client_iface, node, 0, coil, coil_qty);
|
||||||
zassert_equal(err, 0, "FC15 request failed");
|
zassert_equal(err, 0, "FC15 request failed");
|
||||||
|
|
||||||
err = modbus_read_coils(iface, node, 0, coil, coil_qty);
|
err = modbus_read_coils(client_iface, node, 0, coil, coil_qty);
|
||||||
zassert_equal(err, 0, "FC01 request failed");
|
zassert_equal(err, 0, "FC01 request failed");
|
||||||
|
|
||||||
zassert_equal(coil[0], 0xaa, "FC15 verify coil 0-7 failed");
|
zassert_equal(coil[0], 0xaa, "FC15 verify coil 0-7 failed");
|
||||||
zassert_equal(coil[1], 0xbb, "FC15 verify coil 8-15 failed");
|
zassert_equal(coil[1], 0xbb, "FC15 verify coil 8-15 failed");
|
||||||
|
|
||||||
err = modbus_write_coil(iface, node, offset_oor, true);
|
err = modbus_write_coil(client_iface, node, offset_oor, true);
|
||||||
zassert_not_equal(err, 0, "FC05 out of range request not failed");
|
zassert_not_equal(err, 0, "FC05 out of range request not failed");
|
||||||
|
|
||||||
err = modbus_write_coils(iface, node, offset_oor, coil, coil_qty);
|
err = modbus_write_coils(client_iface, node, offset_oor, coil, coil_qty);
|
||||||
zassert_not_equal(err, 0, "FC15 out of range request not failed");
|
zassert_not_equal(err, 0, "FC15 out of range request not failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,16 +62,16 @@ void test_di_rd(void)
|
||||||
uint8_t di[4] = {0};
|
uint8_t di[4] = {0};
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = modbus_read_dinputs(iface, node, 0, di, di_qty);
|
err = modbus_read_dinputs(client_iface, node, 0, di, di_qty);
|
||||||
zassert_equal(err, 0, "FC02 request failed");
|
zassert_equal(err, 0, "FC02 request failed");
|
||||||
|
|
||||||
zassert_equal(di[0], 0xaa, "FC02 verify di 0-7 failed");
|
zassert_equal(di[0], 0xaa, "FC02 verify di 0-7 failed");
|
||||||
zassert_equal(di[1], 0xbb, "FC02 verify di 8-15 failed");
|
zassert_equal(di[1], 0xbb, "FC02 verify di 8-15 failed");
|
||||||
|
|
||||||
err = modbus_read_dinputs(iface, node, 0, di, di_qty + 1);
|
err = modbus_read_dinputs(client_iface, node, 0, di, di_qty + 1);
|
||||||
zassert_not_equal(err, 0, "FC02 out of range request not failed");
|
zassert_not_equal(err, 0, "FC02 out of range request not failed");
|
||||||
|
|
||||||
err = modbus_read_dinputs(iface, node, offset_oor, di, di_qty);
|
err = modbus_read_dinputs(client_iface, node, offset_oor, di, di_qty);
|
||||||
zassert_not_equal(err, 0, "FC02 out of range request not failed");
|
zassert_not_equal(err, 0, "FC02 out of range request not failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,15 +80,15 @@ void test_input_reg(void)
|
||||||
uint16_t ir[8] = {0};
|
uint16_t ir[8] = {0};
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = modbus_write_holding_reg(iface, node, 0, 0xcafe);
|
err = modbus_write_holding_reg(client_iface, node, 0, 0xcafe);
|
||||||
zassert_equal(err, 0, "FC06 write request for FC04 failed");
|
zassert_equal(err, 0, "FC06 write request for FC04 failed");
|
||||||
|
|
||||||
err = modbus_read_input_regs(iface, node, 0, ir, ARRAY_SIZE(ir));
|
err = modbus_read_input_regs(client_iface, node, 0, ir, ARRAY_SIZE(ir));
|
||||||
zassert_equal(err, 0, "FC04 request failed");
|
zassert_equal(err, 0, "FC04 request failed");
|
||||||
|
|
||||||
zassert_equal(ir[0], 0xcafe, "FC04 verify failed");
|
zassert_equal(ir[0], 0xcafe, "FC04 verify failed");
|
||||||
|
|
||||||
err = modbus_read_input_regs(iface,
|
err = modbus_read_input_regs(client_iface,
|
||||||
node,
|
node,
|
||||||
offset_oor,
|
offset_oor,
|
||||||
ir,
|
ir,
|
||||||
|
@ -105,14 +106,14 @@ void test_holding_reg(void)
|
||||||
|
|
||||||
/* Test FC06 | FC03 */
|
/* Test FC06 | FC03 */
|
||||||
for (uint16_t idx = 0; idx < ARRAY_SIZE(hr_wr); idx++) {
|
for (uint16_t idx = 0; idx < ARRAY_SIZE(hr_wr); idx++) {
|
||||||
err = modbus_write_holding_reg(iface, node, idx, hr_wr[idx]);
|
err = modbus_write_holding_reg(client_iface, node, idx, hr_wr[idx]);
|
||||||
zassert_equal(err, 0, "FC06 write request failed");
|
zassert_equal(err, 0, "FC06 write request failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
err = modbus_write_holding_reg(iface, node, offset_oor, 0xcafe);
|
err = modbus_write_holding_reg(client_iface, node, offset_oor, 0xcafe);
|
||||||
zassert_not_equal(err, 0, "FC06 out of range request not failed");
|
zassert_not_equal(err, 0, "FC06 out of range request not failed");
|
||||||
|
|
||||||
err = modbus_read_holding_regs(iface, node, 0,
|
err = modbus_read_holding_regs(client_iface, node, 0,
|
||||||
hr_rd, ARRAY_SIZE(hr_rd));
|
hr_rd, ARRAY_SIZE(hr_rd));
|
||||||
zassert_equal(err, 0, "FC03 read request failed");
|
zassert_equal(err, 0, "FC03 read request failed");
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ void test_holding_reg(void)
|
||||||
zassert_equal(memcmp(hr_wr, hr_rd, sizeof(hr_wr)), 0,
|
zassert_equal(memcmp(hr_wr, hr_rd, sizeof(hr_wr)), 0,
|
||||||
"FC06 verify failed");
|
"FC06 verify failed");
|
||||||
|
|
||||||
err = modbus_read_holding_regs(iface,
|
err = modbus_read_holding_regs(client_iface,
|
||||||
node,
|
node,
|
||||||
offset_oor,
|
offset_oor,
|
||||||
hr_rd,
|
hr_rd,
|
||||||
|
@ -128,11 +129,11 @@ void test_holding_reg(void)
|
||||||
zassert_not_equal(err, 0, "FC03 out of range request not failed");
|
zassert_not_equal(err, 0, "FC03 out of range request not failed");
|
||||||
|
|
||||||
/* Test FC16 | FC03 */
|
/* Test FC16 | FC03 */
|
||||||
err = modbus_write_holding_regs(iface, node, 0,
|
err = modbus_write_holding_regs(client_iface, node, 0,
|
||||||
hr_wr, ARRAY_SIZE(hr_wr));
|
hr_wr, ARRAY_SIZE(hr_wr));
|
||||||
zassert_equal(err, 0, "FC16 write request failed");
|
zassert_equal(err, 0, "FC16 write request failed");
|
||||||
|
|
||||||
err = modbus_read_holding_regs(iface, node, 0,
|
err = modbus_read_holding_regs(client_iface, node, 0,
|
||||||
hr_rd, ARRAY_SIZE(hr_rd));
|
hr_rd, ARRAY_SIZE(hr_rd));
|
||||||
zassert_equal(err, 0, "FC03 read request failed");
|
zassert_equal(err, 0, "FC03 read request failed");
|
||||||
|
|
||||||
|
@ -142,35 +143,35 @@ void test_holding_reg(void)
|
||||||
|
|
||||||
/* Test FC16 | FC03 */
|
/* Test FC16 | FC03 */
|
||||||
for (uint16_t idx = 0; idx < ARRAY_SIZE(fhr_wr); idx++) {
|
for (uint16_t idx = 0; idx < ARRAY_SIZE(fhr_wr); idx++) {
|
||||||
err = modbus_write_holding_regs_fp(iface,
|
err = modbus_write_holding_regs_fp(client_iface,
|
||||||
node,
|
node,
|
||||||
fp_offset + idx,
|
fp_offset + idx,
|
||||||
&fhr_wr[0], 1);
|
&fhr_wr[0], 1);
|
||||||
zassert_equal(err, 0, "FC16 write request failed");
|
zassert_equal(err, 0, "FC16 write request failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
err = modbus_write_holding_regs_fp(iface,
|
err = modbus_write_holding_regs_fp(client_iface,
|
||||||
node,
|
node,
|
||||||
fp_offset,
|
fp_offset,
|
||||||
fhr_wr,
|
fhr_wr,
|
||||||
ARRAY_SIZE(fhr_wr));
|
ARRAY_SIZE(fhr_wr));
|
||||||
zassert_equal(err, 0, "FC16 FP request failed");
|
zassert_equal(err, 0, "FC16 FP request failed");
|
||||||
|
|
||||||
err = modbus_write_holding_regs_fp(iface,
|
err = modbus_write_holding_regs_fp(client_iface,
|
||||||
node,
|
node,
|
||||||
fp_offset_oor,
|
fp_offset_oor,
|
||||||
fhr_wr,
|
fhr_wr,
|
||||||
ARRAY_SIZE(fhr_wr));
|
ARRAY_SIZE(fhr_wr));
|
||||||
zassert_not_equal(err, 0, "FC16 FP out of range request not failed");
|
zassert_not_equal(err, 0, "FC16 FP out of range request not failed");
|
||||||
|
|
||||||
err = modbus_read_holding_regs_fp(iface,
|
err = modbus_read_holding_regs_fp(client_iface,
|
||||||
node,
|
node,
|
||||||
fp_offset_oor,
|
fp_offset_oor,
|
||||||
fhr_wr,
|
fhr_wr,
|
||||||
ARRAY_SIZE(fhr_wr));
|
ARRAY_SIZE(fhr_wr));
|
||||||
zassert_not_equal(err, 0, "FC16 FP out of range request not failed");
|
zassert_not_equal(err, 0, "FC16 FP out of range request not failed");
|
||||||
|
|
||||||
err = modbus_read_holding_regs_fp(iface,
|
err = modbus_read_holding_regs_fp(client_iface,
|
||||||
node,
|
node,
|
||||||
fp_offset,
|
fp_offset,
|
||||||
fhr_rd,
|
fhr_rd,
|
||||||
|
@ -188,51 +189,81 @@ void test_diagnostic(void)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (uint16_t sf = 0x0A; sf < 0x0F; sf++) {
|
for (uint16_t sf = 0x0A; sf < 0x0F; sf++) {
|
||||||
err = modbus_request_diagnostic(iface, node, sf, 0, &data);
|
err = modbus_request_diagnostic(client_iface, node, sf, 0, &data);
|
||||||
zassert_equal(err, 0, "FC08:0x%04x request failed", sf);
|
zassert_equal(err, 0, "FC08:0x%04x request failed", sf);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = modbus_request_diagnostic(iface, node, 0xFF, 0, &data);
|
err = modbus_request_diagnostic(client_iface, node, 0xFF, 0, &data);
|
||||||
zassert_not_equal(err, 0, "FC08 not supported request not failed");
|
zassert_not_equal(err, 0, "FC08 not supported request not failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct modbus_iface_param client_param = {
|
||||||
|
.mode = MODBUS_MODE_RTU,
|
||||||
|
.rx_timeout = MB_TEST_RESPONSE_TO,
|
||||||
|
.serial = {
|
||||||
|
.baud = MB_TEST_BAUDRATE_LOW,
|
||||||
|
.parity = UART_CFG_PARITY_ODD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
void test_client_setup_low_none(void)
|
void test_client_setup_low_none(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(0, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
err = modbus_init_client(iface, MB_TEST_BAUDRATE_LOW,
|
client_iface = modbus_iface_get_by_name(iface_name);
|
||||||
UART_CFG_PARITY_NONE,
|
client_param.mode = MODBUS_MODE_RTU;
|
||||||
MB_TEST_RESPONSE_TO, false);
|
client_param.serial.baud = MB_TEST_BAUDRATE_LOW;
|
||||||
|
client_param.serial.parity = UART_CFG_PARITY_NONE;
|
||||||
|
|
||||||
|
err = modbus_init_client(client_iface, client_param);
|
||||||
zassert_equal(err, 0, "Failed to configure RTU client");
|
zassert_equal(err, 0, "Failed to configure RTU client");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_client_setup_low_odd(void)
|
void test_client_setup_low_odd(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(0, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
err = modbus_init_client(iface, MB_TEST_BAUDRATE_LOW,
|
client_iface = modbus_iface_get_by_name(iface_name);
|
||||||
UART_CFG_PARITY_ODD,
|
client_param.mode = MODBUS_MODE_RTU;
|
||||||
MB_TEST_RESPONSE_TO, false);
|
client_param.serial.baud = MB_TEST_BAUDRATE_LOW;
|
||||||
|
client_param.serial.parity = UART_CFG_PARITY_ODD;
|
||||||
|
|
||||||
|
err = modbus_init_client(client_iface, client_param);
|
||||||
zassert_equal(err, 0, "Failed to configure RTU client");
|
zassert_equal(err, 0, "Failed to configure RTU client");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_client_setup_high_even(void)
|
void test_client_setup_high_even(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(0, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
err = modbus_init_client(iface, MB_TEST_BAUDRATE_HIGH,
|
client_iface = modbus_iface_get_by_name(iface_name);
|
||||||
UART_CFG_PARITY_EVEN,
|
client_param.mode = MODBUS_MODE_RTU;
|
||||||
MB_TEST_RESPONSE_TO, false);
|
client_param.serial.baud = MB_TEST_BAUDRATE_HIGH;
|
||||||
|
client_param.serial.parity = UART_CFG_PARITY_EVEN;
|
||||||
|
|
||||||
|
err = modbus_init_client(client_iface, client_param);
|
||||||
zassert_equal(err, 0, "Failed to configure RTU client");
|
zassert_equal(err, 0, "Failed to configure RTU client");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_client_setup_ascii(void)
|
void test_client_setup_ascii(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(0, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
|
client_iface = modbus_iface_get_by_name(iface_name);
|
||||||
|
client_param.mode = MODBUS_MODE_ASCII;
|
||||||
|
client_param.serial.baud = MB_TEST_BAUDRATE_HIGH;
|
||||||
|
client_param.serial.parity = UART_CFG_PARITY_EVEN;
|
||||||
|
|
||||||
|
err = modbus_init_client(client_iface, client_param);
|
||||||
|
|
||||||
err = modbus_init_client(iface, MB_TEST_BAUDRATE_HIGH,
|
|
||||||
UART_CFG_PARITY_EVEN,
|
|
||||||
MB_TEST_RESPONSE_TO, true);
|
|
||||||
zassert_equal(err, 0, "Failed to configure RTU client");
|
zassert_equal(err, 0, "Failed to configure RTU client");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +271,7 @@ void test_client_disable(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = modbus_disable(iface);
|
err = modbus_disable(client_iface);
|
||||||
zassert_equal(err, 0, "Failed to disable RTU client");
|
zassert_equal(err, 0, "Failed to disable RTU client");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,13 @@ static uint16_t coils;
|
||||||
static uint16_t holding_reg[8];
|
static uint16_t holding_reg[8];
|
||||||
static float holding_fp[4];
|
static float holding_fp[4];
|
||||||
|
|
||||||
|
uint8_t server_iface;
|
||||||
|
|
||||||
|
uint8_t test_get_server_iface(void)
|
||||||
|
{
|
||||||
|
return server_iface;
|
||||||
|
}
|
||||||
|
|
||||||
static int coil_rd(uint16_t addr, bool *state)
|
static int coil_rd(uint16_t addr, bool *state)
|
||||||
{
|
{
|
||||||
if (addr >= (sizeof(coils) * 8)) {
|
if (addr >= (sizeof(coils) * 8)) {
|
||||||
|
@ -164,15 +171,31 @@ static struct modbus_user_callbacks mbs_cbs = {
|
||||||
.holding_reg_wr_fp = holding_reg_wr_fp,
|
.holding_reg_wr_fp = holding_reg_wr_fp,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct modbus_iface_param server_param = {
|
||||||
|
.mode = MODBUS_MODE_RTU,
|
||||||
|
.server = {
|
||||||
|
.user_cb = &mbs_cbs,
|
||||||
|
.unit_id = MB_TEST_NODE_ADDR,
|
||||||
|
},
|
||||||
|
.serial = {
|
||||||
|
.baud = MB_TEST_BAUDRATE_LOW,
|
||||||
|
.parity = UART_CFG_PARITY_ODD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
void test_server_setup_low_odd(void)
|
void test_server_setup_low_odd(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(1, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
|
server_iface = modbus_iface_get_by_name(iface_name);
|
||||||
|
server_param.mode = MODBUS_MODE_RTU;
|
||||||
|
server_param.serial.baud = MB_TEST_BAUDRATE_LOW;
|
||||||
|
server_param.serial.parity = UART_CFG_PARITY_ODD;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
||||||
err = modbus_init_server(MB_TEST_IFACE_SERVER, MB_TEST_NODE_ADDR,
|
err = modbus_init_server(server_iface, server_param);
|
||||||
MB_TEST_BAUDRATE_LOW,
|
|
||||||
UART_CFG_PARITY_ODD,
|
|
||||||
&mbs_cbs, false);
|
|
||||||
zassert_equal(err, 0, "Failed to configure RTU server");
|
zassert_equal(err, 0, "Failed to configure RTU server");
|
||||||
} else {
|
} else {
|
||||||
ztest_test_skip();
|
ztest_test_skip();
|
||||||
|
@ -182,12 +205,16 @@ void test_server_setup_low_odd(void)
|
||||||
void test_server_setup_low_none(void)
|
void test_server_setup_low_none(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(1, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
|
server_iface = modbus_iface_get_by_name(iface_name);
|
||||||
|
server_param.mode = MODBUS_MODE_RTU;
|
||||||
|
server_param.serial.baud = MB_TEST_BAUDRATE_LOW;
|
||||||
|
server_param.serial.parity = UART_CFG_PARITY_NONE;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
||||||
err = modbus_init_server(MB_TEST_IFACE_SERVER, MB_TEST_NODE_ADDR,
|
err = modbus_init_server(server_iface, server_param);
|
||||||
MB_TEST_BAUDRATE_LOW,
|
|
||||||
UART_CFG_PARITY_NONE,
|
|
||||||
&mbs_cbs, false);
|
|
||||||
zassert_equal(err, 0, "Failed to configure RTU server");
|
zassert_equal(err, 0, "Failed to configure RTU server");
|
||||||
} else {
|
} else {
|
||||||
ztest_test_skip();
|
ztest_test_skip();
|
||||||
|
@ -197,12 +224,16 @@ void test_server_setup_low_none(void)
|
||||||
void test_server_setup_high_even(void)
|
void test_server_setup_high_even(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(1, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
|
server_iface = modbus_iface_get_by_name(iface_name);
|
||||||
|
server_param.mode = MODBUS_MODE_RTU;
|
||||||
|
server_param.serial.baud = MB_TEST_BAUDRATE_HIGH;
|
||||||
|
server_param.serial.parity = UART_CFG_PARITY_EVEN;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
||||||
err = modbus_init_server(MB_TEST_IFACE_SERVER, MB_TEST_NODE_ADDR,
|
err = modbus_init_server(server_iface, server_param);
|
||||||
MB_TEST_BAUDRATE_HIGH,
|
|
||||||
UART_CFG_PARITY_EVEN,
|
|
||||||
&mbs_cbs, false);
|
|
||||||
zassert_equal(err, 0, "Failed to configure RTU server");
|
zassert_equal(err, 0, "Failed to configure RTU server");
|
||||||
} else {
|
} else {
|
||||||
ztest_test_skip();
|
ztest_test_skip();
|
||||||
|
@ -212,12 +243,16 @@ void test_server_setup_high_even(void)
|
||||||
void test_server_setup_ascii(void)
|
void test_server_setup_ascii(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
const char iface_name[] = {DT_PROP_OR(DT_INST(1, zephyr_modbus_serial),
|
||||||
|
label, "")};
|
||||||
|
|
||||||
|
server_iface = modbus_iface_get_by_name(iface_name);
|
||||||
|
server_param.mode = MODBUS_MODE_ASCII;
|
||||||
|
server_param.serial.baud = MB_TEST_BAUDRATE_HIGH;
|
||||||
|
server_param.serial.parity = UART_CFG_PARITY_EVEN;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
||||||
err = modbus_init_server(MB_TEST_IFACE_SERVER, MB_TEST_NODE_ADDR,
|
err = modbus_init_server(server_iface, server_param);
|
||||||
MB_TEST_BAUDRATE_HIGH,
|
|
||||||
UART_CFG_PARITY_EVEN,
|
|
||||||
&mbs_cbs, true);
|
|
||||||
zassert_equal(err, 0, "Failed to configure RTU server");
|
zassert_equal(err, 0, "Failed to configure RTU server");
|
||||||
} else {
|
} else {
|
||||||
ztest_test_skip();
|
ztest_test_skip();
|
||||||
|
@ -229,7 +264,7 @@ void test_server_disable(void)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
if (IS_ENABLED(CONFIG_MODBUS_SERVER)) {
|
||||||
err = modbus_disable(MB_TEST_IFACE_SERVER);
|
err = modbus_disable(server_iface);
|
||||||
zassert_equal(err, 0, "Failed to disable RTU server");
|
zassert_equal(err, 0, "Failed to disable RTU server");
|
||||||
} else {
|
} else {
|
||||||
ztest_test_skip();
|
ztest_test_skip();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue