feat(shell): Add commands to configure Modbus
- Implement a new 'modbus' command in the shell. - Add sub-commands 'set_baud', 'set_id', and 'show'. - Add validation for baud rate and slave ID inputs. - The new parameters are applied to the Modbus server at runtime, allowing for live reconfiguration of the communication settings. - The shell backend is set to RTT.
This commit is contained in:
parent
b836f9a2f4
commit
6a9e4773ea
|
|
@ -6,4 +6,4 @@ list(APPEND BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
|
||||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
project(slave_node)
|
project(slave_node)
|
||||||
|
|
||||||
target_sources(app PRIVATE src/main.c)
|
target_sources(app PRIVATE src/main.c src/shell_modbus.c)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/ {
|
/ {
|
||||||
chosen {
|
chosen {
|
||||||
zephyr,console = &rtt;
|
zephyr,console = &rtt;
|
||||||
zephyr,shell-uart = &rtt; // If using shell
|
zephyr,shell = &rtt;
|
||||||
};
|
};
|
||||||
|
|
||||||
rtt: rtt {
|
rtt: rtt {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ CONFIG_UART_CONSOLE=n
|
||||||
CONFIG_RTT_CONSOLE=y
|
CONFIG_RTT_CONSOLE=y
|
||||||
CONFIG_USE_SEGGER_RTT=y
|
CONFIG_USE_SEGGER_RTT=y
|
||||||
|
|
||||||
|
# Enable Shell
|
||||||
|
CONFIG_SHELL=y
|
||||||
|
CONFIG_SHELL_BACKEND_RTT=y
|
||||||
|
|
||||||
# Config modbus
|
# Config modbus
|
||||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||||
CONFIG_MODBUS=y
|
CONFIG_MODBUS=y
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
#include <zephyr/usb/usb_device.h>
|
#include <zephyr/usb/usb_device.h>
|
||||||
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
#include "modbus_bridge.h"
|
||||||
|
|
||||||
LOG_MODULE_REGISTER(mbs_sample, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(mbs_sample, LOG_LEVEL_INF);
|
||||||
|
|
||||||
#define APP_VERSION_MAJOR 1
|
#define APP_VERSION_MAJOR 1
|
||||||
|
|
@ -32,6 +34,20 @@ enum {
|
||||||
|
|
||||||
|
|
||||||
static uint16_t watchdog_timeout_s;
|
static uint16_t watchdog_timeout_s;
|
||||||
|
static int modbus_iface;
|
||||||
|
|
||||||
|
static struct modbus_iface_param server_param = {
|
||||||
|
.mode = MODBUS_MODE_RTU,
|
||||||
|
.server = {
|
||||||
|
.user_cb = NULL, // Will be set later
|
||||||
|
.unit_id = 1,
|
||||||
|
},
|
||||||
|
.serial = {
|
||||||
|
.baud = 19200,
|
||||||
|
.parity = UART_CFG_PARITY_NONE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static int coil_rd(uint16_t addr, bool *state)
|
static int coil_rd(uint16_t addr, bool *state)
|
||||||
{
|
{
|
||||||
|
|
@ -112,33 +128,56 @@ static struct modbus_user_callbacks mbs_cbs = {
|
||||||
.input_reg_rd = input_reg_rd,
|
.input_reg_rd = input_reg_rd,
|
||||||
};
|
};
|
||||||
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial)
|
#define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial)
|
||||||
|
|
||||||
|
int modbus_reconfigure(uint32_t baudrate, uint8_t unit_id)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
LOG_INF("Reconfiguring Modbus: baudrate=%u, id=%u", baudrate, unit_id);
|
||||||
|
|
||||||
|
err = modbus_disable(modbus_iface);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to disable Modbus: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_param.serial.baud = baudrate;
|
||||||
|
server_param.server.unit_id = unit_id;
|
||||||
|
|
||||||
|
err = modbus_init_server(modbus_iface, server_param);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to re-init Modbus server: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t modbus_get_baudrate(void)
|
||||||
|
{
|
||||||
|
return server_param.serial.baud;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t modbus_get_unit_id(void)
|
||||||
|
{
|
||||||
|
return server_param.server.unit_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int init_modbus_server(void)
|
static int init_modbus_server(void)
|
||||||
{
|
{
|
||||||
const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)};
|
const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)};
|
||||||
int iface;
|
|
||||||
|
|
||||||
iface = modbus_iface_get_by_name(iface_name);
|
modbus_iface = modbus_iface_get_by_name(iface_name);
|
||||||
|
if (modbus_iface < 0) {
|
||||||
if (iface < 0) {
|
|
||||||
LOG_ERR("Failed to get iface index for %s", iface_name);
|
LOG_ERR("Failed to get iface index for %s", iface_name);
|
||||||
return iface;
|
return modbus_iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
return modbus_init_server(iface, server_param);
|
server_param.server.user_cb = &mbs_cbs;
|
||||||
|
|
||||||
|
return modbus_init_server(modbus_iface, server_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
|
@ -154,4 +193,4 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef MODBUS_BRIDGE_H
|
||||||
|
#define MODBUS_BRIDGE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reconfigures the Modbus server with new parameters.
|
||||||
|
*
|
||||||
|
* @param baudrate New baudrate.
|
||||||
|
* @param unit_id New slave unit ID.
|
||||||
|
* @return 0 on success, negative error code on failure.
|
||||||
|
*/
|
||||||
|
int modbus_reconfigure(uint32_t baudrate, uint8_t unit_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the currently active Modbus baudrate.
|
||||||
|
* @return The current baudrate.
|
||||||
|
*/
|
||||||
|
uint32_t modbus_get_baudrate(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the currently active Modbus slave unit ID.
|
||||||
|
* @return The current slave unit ID.
|
||||||
|
*/
|
||||||
|
uint8_t modbus_get_unit_id(void);
|
||||||
|
|
||||||
|
#endif // MODBUS_BRIDGE_H
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include <zephyr/shell/shell.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "modbus_bridge.h"
|
||||||
|
|
||||||
|
static int cmd_modbus_set_baud(const struct shell *sh, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 2) {
|
||||||
|
shell_error(sh, "Usage: set_baud <baudrate>");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t new_baud = (uint32_t)strtoul(argv[1], NULL, 10);
|
||||||
|
const uint32_t valid_baud_rates[] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
|
||||||
|
bool is_valid = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(valid_baud_rates); i++) {
|
||||||
|
if (new_baud == valid_baud_rates[i]) {
|
||||||
|
is_valid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_valid) {
|
||||||
|
char error_msg[128];
|
||||||
|
int offset = snprintf(error_msg, sizeof(error_msg), "Invalid baudrate. Valid rates are: ");
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(valid_baud_rates); i++) {
|
||||||
|
offset += snprintf(error_msg + offset, sizeof(error_msg) - offset, "%u ", valid_baud_rates[i]);
|
||||||
|
}
|
||||||
|
shell_error(sh, "%s", error_msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modbus_reconfigure(new_baud, modbus_get_unit_id()) != 0) {
|
||||||
|
shell_error(sh, "Failed to apply new baudrate");
|
||||||
|
} else {
|
||||||
|
shell_print(sh, "Modbus baudrate set to: %u", new_baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_modbus_set_id(const struct shell *sh, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 2) {
|
||||||
|
shell_error(sh, "Usage: set_id <slave_id>");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t new_id = (uint32_t)strtoul(argv[1], NULL, 10);
|
||||||
|
if (new_id == 0 || new_id > 247) {
|
||||||
|
shell_error(sh, "Invalid slave ID: %s. Must be between 1 and 247.", argv[1]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modbus_reconfigure(modbus_get_baudrate(), (uint8_t)new_id) != 0) {
|
||||||
|
shell_error(sh, "Failed to apply new slave ID");
|
||||||
|
} else {
|
||||||
|
shell_print(sh, "Modbus slave ID set to: %u", (uint8_t)new_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_modbus_show(const struct shell *sh, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
shell_print(sh, "Current Modbus Configuration:");
|
||||||
|
shell_print(sh, " Baudrate: %u", modbus_get_baudrate());
|
||||||
|
shell_print(sh, " Slave ID: %u", modbus_get_unit_id());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_STATIC_SUBCMD_SET_CREATE(sub_modbus_cmds,
|
||||||
|
SHELL_CMD(set_baud, NULL, "Set Modbus baudrate", cmd_modbus_set_baud),
|
||||||
|
SHELL_CMD(set_id, NULL, "Set Modbus slave ID", cmd_modbus_set_id),
|
||||||
|
SHELL_CMD(show, NULL, "Show current Modbus configuration", cmd_modbus_show),
|
||||||
|
SHELL_SUBCMD_SET_END
|
||||||
|
);
|
||||||
|
|
||||||
|
SHELL_CMD_REGISTER(modbus, &sub_modbus_cmds, "Modbus configuration", NULL);
|
||||||
Loading…
Reference in New Issue