modbus: move serial line config outside context
Move serial line config outside context. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
parent
3ddb47cc43
commit
b132ab556c
3 changed files with 145 additions and 113 deletions
|
@ -34,13 +34,21 @@ DT_INST_FOREACH_STATUS_OKAY(MB_RTU_DEFINE_GPIO_CFGS)
|
||||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, d), \
|
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, d), \
|
||||||
(&d##_cfg_##n), (NULL))
|
(&d##_cfg_##n), (NULL))
|
||||||
|
|
||||||
#define MODBUS_DT_GET_DEV(n) { \
|
#define MODBUS_DT_GET_SERIAL_DEV(n) { \
|
||||||
.iface_name = DT_INST_LABEL(n), \
|
|
||||||
.dev_name = DT_INST_BUS_LABEL(n), \
|
.dev_name = DT_INST_BUS_LABEL(n), \
|
||||||
.de = MB_RTU_ASSIGN_GPIO_CFG(n, de_gpios), \
|
.de = MB_RTU_ASSIGN_GPIO_CFG(n, de_gpios), \
|
||||||
.re = MB_RTU_ASSIGN_GPIO_CFG(n, re_gpios), \
|
.re = MB_RTU_ASSIGN_GPIO_CFG(n, re_gpios), \
|
||||||
},
|
},
|
||||||
|
|
||||||
|
static struct modbus_serial_config modbus_serial_cfg[] = {
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(MODBUS_DT_GET_SERIAL_DEV)
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MODBUS_DT_GET_DEV(n) { \
|
||||||
|
.iface_name = DT_INST_LABEL(n), \
|
||||||
|
.cfg = &modbus_serial_cfg[n], \
|
||||||
|
},
|
||||||
|
|
||||||
static struct modbus_context mb_ctx_tbl[] = {
|
static struct modbus_context mb_ctx_tbl[] = {
|
||||||
DT_INST_FOREACH_STATUS_OKAY(MODBUS_DT_GET_DEV)
|
DT_INST_FOREACH_STATUS_OKAY(MODBUS_DT_GET_DEV)
|
||||||
};
|
};
|
||||||
|
@ -156,9 +164,6 @@ static struct modbus_context *mb_cfg_iface(const uint8_t iface,
|
||||||
ctx->mbs_user_cb = NULL;
|
ctx->mbs_user_cb = NULL;
|
||||||
k_mutex_init(&ctx->iface_lock);
|
k_mutex_init(&ctx->iface_lock);
|
||||||
|
|
||||||
ctx->uart_buf_ctr = 0;
|
|
||||||
ctx->uart_buf_ptr = &ctx->uart_buf[0];
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -91,33 +92,44 @@ enum modbus_mode {
|
||||||
MODBUS_MODE_ASCII,
|
MODBUS_MODE_ASCII,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MODBUS_STATE_CONFIGURED 0
|
struct modbus_serial_config {
|
||||||
|
|
||||||
struct modbus_context {
|
|
||||||
/* Interface name */
|
|
||||||
const char *iface_name;
|
|
||||||
/* UART device name */
|
/* UART device name */
|
||||||
const char *dev_name;
|
const char *dev_name;
|
||||||
/* UART device */
|
/* UART device */
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
/* MODBUS mode */
|
|
||||||
enum modbus_mode mode;
|
|
||||||
/* True if interface is configured as client */
|
|
||||||
bool client;
|
|
||||||
/* Amount of time client is willing to wait for response from server */
|
|
||||||
uint32_t rxwait_to;
|
|
||||||
/* RTU timeout (maximum inter-frame delay) */
|
/* RTU timeout (maximum inter-frame delay) */
|
||||||
uint32_t rtu_timeout;
|
uint32_t rtu_timeout;
|
||||||
/* Pointer to user server callbacks */
|
|
||||||
struct modbus_user_callbacks *mbs_user_cb;
|
|
||||||
/* Interface state */
|
|
||||||
atomic_t state;
|
|
||||||
/* Pointer to current position in buffer */
|
/* Pointer to current position in buffer */
|
||||||
uint8_t *uart_buf_ptr;
|
uint8_t *uart_buf_ptr;
|
||||||
/* Pointer to driver enable (DE) pin config */
|
/* Pointer to driver enable (DE) pin config */
|
||||||
struct mb_rtu_gpio_config *de;
|
struct mb_rtu_gpio_config *de;
|
||||||
/* Pointer to receiver enable (nRE) pin config */
|
/* Pointer to receiver enable (nRE) pin config */
|
||||||
struct mb_rtu_gpio_config *re;
|
struct mb_rtu_gpio_config *re;
|
||||||
|
/* RTU timer to detect frame end point */
|
||||||
|
struct k_timer rtu_timer;
|
||||||
|
/* Number of bytes received or to send */
|
||||||
|
uint16_t uart_buf_ctr;
|
||||||
|
/* Storage of received characters or characters to send */
|
||||||
|
uint8_t uart_buf[CONFIG_MODBUS_BUFFER_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MODBUS_STATE_CONFIGURED 0
|
||||||
|
|
||||||
|
struct modbus_context {
|
||||||
|
/* Interface name */
|
||||||
|
const char *iface_name;
|
||||||
|
/* Serial line configuration */
|
||||||
|
struct modbus_serial_config *cfg;
|
||||||
|
/* MODBUS mode */
|
||||||
|
enum modbus_mode mode;
|
||||||
|
/* True if interface is configured as client */
|
||||||
|
bool client;
|
||||||
|
/* Amount of time client is willing to wait for response from server */
|
||||||
|
uint32_t rxwait_to;
|
||||||
|
/* Pointer to user server callbacks */
|
||||||
|
struct modbus_user_callbacks *mbs_user_cb;
|
||||||
|
/* Interface state */
|
||||||
|
atomic_t state;
|
||||||
|
|
||||||
/* Client's mutually exclusive access */
|
/* Client's mutually exclusive access */
|
||||||
struct k_mutex iface_lock;
|
struct k_mutex iface_lock;
|
||||||
|
@ -125,15 +137,11 @@ struct modbus_context {
|
||||||
struct k_sem client_wait_sem;
|
struct k_sem client_wait_sem;
|
||||||
/* Server work item */
|
/* Server work item */
|
||||||
struct k_work server_work;
|
struct k_work server_work;
|
||||||
/* RTU timer to detect frame end point */
|
|
||||||
struct k_timer rtu_timer;
|
|
||||||
/* Received frame */
|
/* Received frame */
|
||||||
struct mb_rtu_frame rx_frame;
|
struct mb_rtu_frame rx_frame;
|
||||||
/* Frame to transmit */
|
/* Frame to transmit */
|
||||||
struct mb_rtu_frame tx_frame;
|
struct mb_rtu_frame tx_frame;
|
||||||
|
|
||||||
/* Number of bytes received or to send */
|
|
||||||
uint16_t uart_buf_ctr;
|
|
||||||
/* Records error from frame reception, e.g. CRC error */
|
/* Records error from frame reception, e.g. CRC error */
|
||||||
int rx_frame_err;
|
int rx_frame_err;
|
||||||
|
|
||||||
|
@ -146,8 +154,6 @@ struct modbus_context {
|
||||||
#endif
|
#endif
|
||||||
/* Node address */
|
/* Node address */
|
||||||
uint8_t node_addr;
|
uint8_t node_addr;
|
||||||
/* Storage of received characters or characters to send */
|
|
||||||
uint8_t uart_buf[CONFIG_MODBUS_BUFFER_SIZE];
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,35 +30,43 @@ LOG_MODULE_REGISTER(modbus_serial, CONFIG_MODBUS_LOG_LEVEL);
|
||||||
|
|
||||||
static void modbus_serial_tx_on(struct modbus_context *ctx)
|
static void modbus_serial_tx_on(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->de != NULL) {
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
gpio_pin_set(ctx->de->dev, ctx->de->pin, 1);
|
|
||||||
|
if (cfg->de != NULL) {
|
||||||
|
gpio_pin_set(cfg->de->dev, cfg->de->pin, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_irq_tx_enable(ctx->dev);
|
uart_irq_tx_enable(cfg->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void modbus_serial_tx_off(struct modbus_context *ctx)
|
static void modbus_serial_tx_off(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
uart_irq_tx_disable(ctx->dev);
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
if (ctx->de != NULL) {
|
|
||||||
gpio_pin_set(ctx->de->dev, ctx->de->pin, 0);
|
uart_irq_tx_disable(cfg->dev);
|
||||||
|
if (cfg->de != NULL) {
|
||||||
|
gpio_pin_set(cfg->de->dev, cfg->de->pin, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void modbus_serial_rx_on(struct modbus_context *ctx)
|
static void modbus_serial_rx_on(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->re != NULL) {
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
gpio_pin_set(ctx->re->dev, ctx->re->pin, 1);
|
|
||||||
|
if (cfg->re != NULL) {
|
||||||
|
gpio_pin_set(cfg->re->dev, cfg->re->pin, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_irq_rx_enable(ctx->dev);
|
uart_irq_rx_enable(cfg->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void modbus_serial_rx_off(struct modbus_context *ctx)
|
static void modbus_serial_rx_off(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
uart_irq_rx_disable(ctx->dev);
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
if (ctx->re != NULL) {
|
|
||||||
gpio_pin_set(ctx->re->dev, ctx->re->pin, 0);
|
uart_irq_rx_disable(cfg->dev);
|
||||||
|
if (cfg->re != NULL) {
|
||||||
|
gpio_pin_set(cfg->re->dev, cfg->re->pin, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,13 +97,14 @@ static uint8_t modbus_ascii_get_lrc(uint8_t *src, size_t length)
|
||||||
/* Parses and converts an ASCII mode frame into a Modbus RTU frame. */
|
/* Parses and converts an ASCII mode frame into a Modbus RTU frame. */
|
||||||
static int modbus_ascii_rx_frame(struct modbus_context *ctx)
|
static int modbus_ascii_rx_frame(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
uint8_t *pmsg;
|
uint8_t *pmsg;
|
||||||
uint8_t *prx_data;
|
uint8_t *prx_data;
|
||||||
uint16_t rx_size;
|
uint16_t rx_size;
|
||||||
uint8_t frame_lrc;
|
uint8_t frame_lrc;
|
||||||
uint8_t calc_lrc;
|
uint8_t calc_lrc;
|
||||||
|
|
||||||
rx_size = ctx->uart_buf_ctr;
|
rx_size = cfg->uart_buf_ctr;
|
||||||
prx_data = &ctx->rx_frame.data[0];
|
prx_data = &ctx->rx_frame.data[0];
|
||||||
|
|
||||||
if (!(rx_size & 0x01)) {
|
if (!(rx_size & 0x01)) {
|
||||||
|
@ -108,9 +117,9 @@ static int modbus_ascii_rx_frame(struct modbus_context *ctx)
|
||||||
return -EMSGSIZE;
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ctx->uart_buf[0] != MODBUS_ASCII_START_FRAME_CHAR) ||
|
if ((cfg->uart_buf[0] != MODBUS_ASCII_START_FRAME_CHAR) ||
|
||||||
(ctx->uart_buf[rx_size - 2] != MODBUS_ASCII_END_FRAME_CHAR1) ||
|
(cfg->uart_buf[rx_size - 2] != MODBUS_ASCII_END_FRAME_CHAR1) ||
|
||||||
(ctx->uart_buf[rx_size - 1] != MODBUS_ASCII_END_FRAME_CHAR2)) {
|
(cfg->uart_buf[rx_size - 1] != MODBUS_ASCII_END_FRAME_CHAR2)) {
|
||||||
LOG_WRN("Frame character error");
|
LOG_WRN("Frame character error");
|
||||||
return -EMSGSIZE;
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +127,7 @@ static int modbus_ascii_rx_frame(struct modbus_context *ctx)
|
||||||
/* Take away for the ':', CR, and LF */
|
/* Take away for the ':', CR, and LF */
|
||||||
rx_size -= 3;
|
rx_size -= 3;
|
||||||
/* Point past the ':' to the address. */
|
/* Point past the ':' to the address. */
|
||||||
pmsg = &ctx->uart_buf[1];
|
pmsg = &cfg->uart_buf[1];
|
||||||
|
|
||||||
hex2bin(pmsg, 2, &ctx->rx_frame.addr, 1);
|
hex2bin(pmsg, 2, &ctx->rx_frame.addr, 1);
|
||||||
pmsg += 2;
|
pmsg += 2;
|
||||||
|
@ -148,8 +157,8 @@ static int modbus_ascii_rx_frame(struct modbus_context *ctx)
|
||||||
* by the sender. We thus need to subtract 5 'ASCII' characters
|
* by the sender. We thus need to subtract 5 'ASCII' characters
|
||||||
* from the received message to exclude these.
|
* from the received message to exclude these.
|
||||||
*/
|
*/
|
||||||
calc_lrc = modbus_ascii_get_lrc(&ctx->uart_buf[1],
|
calc_lrc = modbus_ascii_get_lrc(&cfg->uart_buf[1],
|
||||||
(ctx->uart_buf_ctr - 5) / 2);
|
(cfg->uart_buf_ctr - 5) / 2);
|
||||||
|
|
||||||
if (calc_lrc != frame_lrc) {
|
if (calc_lrc != frame_lrc) {
|
||||||
LOG_ERR("Calculated LRC does not match received LRC");
|
LOG_ERR("Calculated LRC does not match received LRC");
|
||||||
|
@ -174,15 +183,16 @@ static uint8_t *modbus_ascii_bin2hex(uint8_t value, uint8_t *pbuf)
|
||||||
|
|
||||||
static void modbus_ascii_tx_frame(struct modbus_context *ctx)
|
static void modbus_ascii_tx_frame(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
uint16_t tx_bytes = 0;
|
uint16_t tx_bytes = 0;
|
||||||
uint8_t lrc;
|
uint8_t lrc;
|
||||||
uint8_t *pbuf;
|
uint8_t *pbuf;
|
||||||
|
|
||||||
/* Place the start-of-frame character into output buffer */
|
/* Place the start-of-frame character into output buffer */
|
||||||
ctx->uart_buf[0] = MODBUS_ASCII_START_FRAME_CHAR;
|
cfg->uart_buf[0] = MODBUS_ASCII_START_FRAME_CHAR;
|
||||||
tx_bytes = 1;
|
tx_bytes = 1;
|
||||||
|
|
||||||
pbuf = &ctx->uart_buf[1];
|
pbuf = &cfg->uart_buf[1];
|
||||||
pbuf = modbus_ascii_bin2hex(ctx->tx_frame.addr, pbuf);
|
pbuf = modbus_ascii_bin2hex(ctx->tx_frame.addr, pbuf);
|
||||||
tx_bytes += 2;
|
tx_bytes += 2;
|
||||||
pbuf = modbus_ascii_bin2hex(ctx->tx_frame.fc, pbuf);
|
pbuf = modbus_ascii_bin2hex(ctx->tx_frame.fc, pbuf);
|
||||||
|
@ -201,7 +211,7 @@ static void modbus_ascii_tx_frame(struct modbus_context *ctx)
|
||||||
* Thus we subtract 1 ASCII character from the LRC.
|
* Thus we subtract 1 ASCII character from the LRC.
|
||||||
* The LRC and CR/LF bytes are not YET in the .uart_buf[].
|
* The LRC and CR/LF bytes are not YET in the .uart_buf[].
|
||||||
*/
|
*/
|
||||||
lrc = modbus_ascii_get_lrc(&ctx->uart_buf[1], (tx_bytes - 1) / 2);
|
lrc = modbus_ascii_get_lrc(&cfg->uart_buf[1], (tx_bytes - 1) / 2);
|
||||||
pbuf = modbus_ascii_bin2hex(lrc, pbuf);
|
pbuf = modbus_ascii_bin2hex(lrc, pbuf);
|
||||||
tx_bytes += 2;
|
tx_bytes += 2;
|
||||||
|
|
||||||
|
@ -210,8 +220,8 @@ static void modbus_ascii_tx_frame(struct modbus_context *ctx)
|
||||||
tx_bytes += 2;
|
tx_bytes += 2;
|
||||||
|
|
||||||
/* Update the total number of bytes to send */
|
/* Update the total number of bytes to send */
|
||||||
ctx->uart_buf_ctr = tx_bytes;
|
cfg->uart_buf_ctr = tx_bytes;
|
||||||
ctx->uart_buf_ptr = &ctx->uart_buf[0];
|
cfg->uart_buf_ptr = &cfg->uart_buf[0];
|
||||||
|
|
||||||
LOG_DBG("Start frame transmission");
|
LOG_DBG("Start frame transmission");
|
||||||
modbus_serial_rx_off(ctx);
|
modbus_serial_rx_off(ctx);
|
||||||
|
@ -262,31 +272,32 @@ static uint16_t modbus_rtu_crc16(uint8_t *src, size_t length)
|
||||||
/* Copy Modbus RTU frame and check if the CRC is valid. */
|
/* Copy Modbus RTU frame and check if the CRC is valid. */
|
||||||
static int modbus_rtu_rx_frame(struct modbus_context *ctx)
|
static int modbus_rtu_rx_frame(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
uint16_t calc_crc;
|
uint16_t calc_crc;
|
||||||
uint16_t crc_idx;
|
uint16_t crc_idx;
|
||||||
uint8_t *data_ptr;
|
uint8_t *data_ptr;
|
||||||
|
|
||||||
/* Is the message long enough? */
|
/* Is the message long enough? */
|
||||||
if ((ctx->uart_buf_ctr < MODBUS_RTU_MIN_MSG_SIZE) ||
|
if ((cfg->uart_buf_ctr < MODBUS_RTU_MIN_MSG_SIZE) ||
|
||||||
(ctx->uart_buf_ctr > CONFIG_MODBUS_BUFFER_SIZE)) {
|
(cfg->uart_buf_ctr > CONFIG_MODBUS_BUFFER_SIZE)) {
|
||||||
LOG_WRN("Frame length error");
|
LOG_WRN("Frame length error");
|
||||||
return -EMSGSIZE;
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->rx_frame.addr = ctx->uart_buf[0];
|
ctx->rx_frame.addr = cfg->uart_buf[0];
|
||||||
ctx->rx_frame.fc = ctx->uart_buf[1];
|
ctx->rx_frame.fc = cfg->uart_buf[1];
|
||||||
data_ptr = &ctx->uart_buf[2];
|
data_ptr = &cfg->uart_buf[2];
|
||||||
/* Payload length without node address, function code, and CRC */
|
/* Payload length without node address, function code, and CRC */
|
||||||
ctx->rx_frame.length = ctx->uart_buf_ctr - 4;
|
ctx->rx_frame.length = cfg->uart_buf_ctr - 4;
|
||||||
/* CRC index */
|
/* CRC index */
|
||||||
crc_idx = ctx->uart_buf_ctr - sizeof(uint16_t);
|
crc_idx = cfg->uart_buf_ctr - sizeof(uint16_t);
|
||||||
|
|
||||||
memcpy(ctx->rx_frame.data, data_ptr, ctx->rx_frame.length);
|
memcpy(ctx->rx_frame.data, data_ptr, ctx->rx_frame.length);
|
||||||
|
|
||||||
ctx->rx_frame.crc = sys_get_le16(&ctx->uart_buf[crc_idx]);
|
ctx->rx_frame.crc = sys_get_le16(&cfg->uart_buf[crc_idx]);
|
||||||
/* Calculate CRC over address, function code, and payload */
|
/* Calculate CRC over address, function code, and payload */
|
||||||
calc_crc = modbus_rtu_crc16(&ctx->uart_buf[0],
|
calc_crc = modbus_rtu_crc16(&cfg->uart_buf[0],
|
||||||
ctx->uart_buf_ctr - sizeof(ctx->rx_frame.crc));
|
cfg->uart_buf_ctr - sizeof(ctx->rx_frame.crc));
|
||||||
|
|
||||||
if (ctx->rx_frame.crc != calc_crc) {
|
if (ctx->rx_frame.crc != calc_crc) {
|
||||||
LOG_WRN("Calculated CRC does not match received CRC");
|
LOG_WRN("Calculated CRC does not match received CRC");
|
||||||
|
@ -298,26 +309,27 @@ static int modbus_rtu_rx_frame(struct modbus_context *ctx)
|
||||||
|
|
||||||
static void rtu_tx_frame(struct modbus_context *ctx)
|
static void rtu_tx_frame(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
uint16_t tx_bytes = 0;
|
uint16_t tx_bytes = 0;
|
||||||
uint8_t *data_ptr;
|
uint8_t *data_ptr;
|
||||||
|
|
||||||
ctx->uart_buf[0] = ctx->tx_frame.addr;
|
cfg->uart_buf[0] = ctx->tx_frame.addr;
|
||||||
ctx->uart_buf[1] = ctx->tx_frame.fc;
|
cfg->uart_buf[1] = ctx->tx_frame.fc;
|
||||||
tx_bytes = 2 + ctx->tx_frame.length;
|
tx_bytes = 2 + ctx->tx_frame.length;
|
||||||
data_ptr = &ctx->uart_buf[2];
|
data_ptr = &cfg->uart_buf[2];
|
||||||
|
|
||||||
memcpy(data_ptr, ctx->tx_frame.data, ctx->tx_frame.length);
|
memcpy(data_ptr, ctx->tx_frame.data, ctx->tx_frame.length);
|
||||||
|
|
||||||
ctx->tx_frame.crc = modbus_rtu_crc16(&ctx->uart_buf[0],
|
ctx->tx_frame.crc = modbus_rtu_crc16(&cfg->uart_buf[0],
|
||||||
ctx->tx_frame.length + 2);
|
ctx->tx_frame.length + 2);
|
||||||
sys_put_le16(ctx->tx_frame.crc,
|
sys_put_le16(ctx->tx_frame.crc,
|
||||||
&ctx->uart_buf[ctx->tx_frame.length + 2]);
|
&cfg->uart_buf[ctx->tx_frame.length + 2]);
|
||||||
tx_bytes += 2;
|
tx_bytes += 2;
|
||||||
|
|
||||||
ctx->uart_buf_ctr = tx_bytes;
|
cfg->uart_buf_ctr = tx_bytes;
|
||||||
ctx->uart_buf_ptr = &ctx->uart_buf[0];
|
cfg->uart_buf_ptr = &cfg->uart_buf[0];
|
||||||
|
|
||||||
LOG_HEXDUMP_DBG(ctx->uart_buf, ctx->uart_buf_ctr, "uart_buf");
|
LOG_HEXDUMP_DBG(cfg->uart_buf, cfg->uart_buf_ctr, "uart_buf");
|
||||||
LOG_DBG("Start frame transmission");
|
LOG_DBG("Start frame transmission");
|
||||||
modbus_serial_rx_off(ctx);
|
modbus_serial_rx_off(ctx);
|
||||||
modbus_serial_tx_on(ctx);
|
modbus_serial_tx_on(ctx);
|
||||||
|
@ -329,24 +341,26 @@ static void rtu_tx_frame(struct modbus_context *ctx)
|
||||||
*/
|
*/
|
||||||
static void cb_handler_rx(struct modbus_context *ctx)
|
static void cb_handler_rx(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
|
|
||||||
if ((ctx->mode == MODBUS_MODE_ASCII) &&
|
if ((ctx->mode == MODBUS_MODE_ASCII) &&
|
||||||
IS_ENABLED(CONFIG_MODBUS_ASCII_MODE)) {
|
IS_ENABLED(CONFIG_MODBUS_ASCII_MODE)) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
|
|
||||||
if (uart_fifo_read(ctx->dev, &c, 1) != 1) {
|
if (uart_fifo_read(cfg->dev, &c, 1) != 1) {
|
||||||
LOG_ERR("Failed to read UART");
|
LOG_ERR("Failed to read UART");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == MODBUS_ASCII_START_FRAME_CHAR) {
|
if (c == MODBUS_ASCII_START_FRAME_CHAR) {
|
||||||
/* Restart a new frame */
|
/* Restart a new frame */
|
||||||
ctx->uart_buf_ptr = &ctx->uart_buf[0];
|
cfg->uart_buf_ptr = &cfg->uart_buf[0];
|
||||||
ctx->uart_buf_ctr = 0;
|
cfg->uart_buf_ctr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->uart_buf_ctr < CONFIG_MODBUS_BUFFER_SIZE) {
|
if (cfg->uart_buf_ctr < CONFIG_MODBUS_BUFFER_SIZE) {
|
||||||
*ctx->uart_buf_ptr++ = c;
|
*cfg->uart_buf_ptr++ = c;
|
||||||
ctx->uart_buf_ctr++;
|
cfg->uart_buf_ctr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == MODBUS_ASCII_END_FRAME_CHAR2) {
|
if (c == MODBUS_ASCII_END_FRAME_CHAR2) {
|
||||||
|
@ -357,30 +371,31 @@ static void cb_handler_rx(struct modbus_context *ctx)
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
/* Restart timer on a new character */
|
/* Restart timer on a new character */
|
||||||
k_timer_start(&ctx->rtu_timer,
|
k_timer_start(&cfg->rtu_timer,
|
||||||
K_USEC(ctx->rtu_timeout), K_NO_WAIT);
|
K_USEC(cfg->rtu_timeout), K_NO_WAIT);
|
||||||
|
|
||||||
n = uart_fifo_read(ctx->dev, ctx->uart_buf_ptr,
|
n = uart_fifo_read(cfg->dev, cfg->uart_buf_ptr,
|
||||||
(CONFIG_MODBUS_BUFFER_SIZE -
|
(CONFIG_MODBUS_BUFFER_SIZE -
|
||||||
ctx->uart_buf_ctr));
|
cfg->uart_buf_ctr));
|
||||||
|
|
||||||
ctx->uart_buf_ptr += n;
|
cfg->uart_buf_ptr += n;
|
||||||
ctx->uart_buf_ctr += n;
|
cfg->uart_buf_ctr += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cb_handler_tx(struct modbus_context *ctx)
|
static void cb_handler_tx(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (ctx->uart_buf_ctr > 0) {
|
if (cfg->uart_buf_ctr > 0) {
|
||||||
n = uart_fifo_fill(ctx->dev, ctx->uart_buf_ptr,
|
n = uart_fifo_fill(cfg->dev, cfg->uart_buf_ptr,
|
||||||
ctx->uart_buf_ctr);
|
cfg->uart_buf_ctr);
|
||||||
ctx->uart_buf_ctr -= n;
|
cfg->uart_buf_ctr -= n;
|
||||||
ctx->uart_buf_ptr += n;
|
cfg->uart_buf_ptr += n;
|
||||||
} else {
|
} else {
|
||||||
/* Disable transmission */
|
/* Disable transmission */
|
||||||
ctx->uart_buf_ptr = &ctx->uart_buf[0];
|
cfg->uart_buf_ptr = &cfg->uart_buf[0];
|
||||||
modbus_serial_tx_off(ctx);
|
modbus_serial_tx_off(ctx);
|
||||||
modbus_serial_rx_on(ctx);
|
modbus_serial_rx_on(ctx);
|
||||||
}
|
}
|
||||||
|
@ -389,19 +404,20 @@ static void cb_handler_tx(struct modbus_context *ctx)
|
||||||
static void uart_cb_handler(const struct device *dev, void *app_data)
|
static void uart_cb_handler(const struct device *dev, void *app_data)
|
||||||
{
|
{
|
||||||
struct modbus_context *ctx = (struct modbus_context *)app_data;
|
struct modbus_context *ctx = (struct modbus_context *)app_data;
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
|
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
LOG_ERR("Modbus hardware is not properly initialized");
|
LOG_ERR("Modbus hardware is not properly initialized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (uart_irq_update(ctx->dev) && uart_irq_is_pending(ctx->dev)) {
|
while (uart_irq_update(cfg->dev) && uart_irq_is_pending(cfg->dev)) {
|
||||||
|
|
||||||
if (uart_irq_rx_ready(ctx->dev)) {
|
if (uart_irq_rx_ready(cfg->dev)) {
|
||||||
cb_handler_rx(ctx);
|
cb_handler_rx(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uart_irq_tx_ready(ctx->dev)) {
|
if (uart_irq_tx_ready(cfg->dev)) {
|
||||||
cb_handler_tx(ctx);
|
cb_handler_tx(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,27 +440,29 @@ static void rtu_tmr_handler(struct k_timer *t_id)
|
||||||
|
|
||||||
static int configure_gpio(struct modbus_context *ctx)
|
static int configure_gpio(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->de != NULL) {
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
ctx->de->dev = device_get_binding(ctx->de->name);
|
|
||||||
if (ctx->de->dev == NULL) {
|
if (cfg->de != NULL) {
|
||||||
|
cfg->de->dev = device_get_binding(cfg->de->name);
|
||||||
|
if (cfg->de->dev == NULL) {
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_pin_configure(ctx->de->dev, ctx->de->pin,
|
if (gpio_pin_configure(cfg->de->dev, cfg->de->pin,
|
||||||
GPIO_OUTPUT_INACTIVE | ctx->de->flags)) {
|
GPIO_OUTPUT_INACTIVE | cfg->de->flags)) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (ctx->re != NULL) {
|
if (cfg->re != NULL) {
|
||||||
ctx->re->dev = device_get_binding(ctx->re->name);
|
cfg->re->dev = device_get_binding(cfg->re->name);
|
||||||
if (ctx->re->dev == NULL) {
|
if (cfg->re->dev == NULL) {
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_pin_configure(ctx->re->dev, ctx->re->pin,
|
if (gpio_pin_configure(cfg->re->dev, cfg->re->pin,
|
||||||
GPIO_OUTPUT_INACTIVE | ctx->re->flags)) {
|
GPIO_OUTPUT_INACTIVE | cfg->re->flags)) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,6 +482,7 @@ void modbus_serial_rx_enable(struct modbus_context *ctx)
|
||||||
|
|
||||||
int modbus_serial_rx_frame(struct modbus_context *ctx)
|
int modbus_serial_rx_frame(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct modbus_serial_config *cfg = ctx->cfg;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
switch (ctx->mode) {
|
switch (ctx->mode) {
|
||||||
|
@ -482,8 +501,8 @@ int modbus_serial_rx_frame(struct modbus_context *ctx)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->uart_buf_ctr = 0;
|
cfg->uart_buf_ctr = 0;
|
||||||
ctx->uart_buf_ptr = &ctx->uart_buf[0];
|
cfg->uart_buf_ptr = &cfg->uart_buf[0];
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -511,14 +530,15 @@ int modbus_serial_init(struct modbus_context *ctx,
|
||||||
enum uart_config_parity parity,
|
enum uart_config_parity parity,
|
||||||
const bool ascii_mode)
|
const bool ascii_mode)
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
ctx->dev = device_get_binding(ctx->dev_name);
|
cfg->dev = device_get_binding(cfg->dev_name);
|
||||||
if (ctx->dev == NULL) {
|
if (cfg->dev == NULL) {
|
||||||
LOG_ERR("Failed to get UART device %s",
|
LOG_ERR("Failed to get UART device %s",
|
||||||
log_strdup(ctx->dev_name));
|
log_strdup(cfg->dev_name));
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,28 +566,30 @@ int modbus_serial_init(struct modbus_context *ctx,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uart_configure(ctx->dev, &uart_cfg) != 0) {
|
if (uart_configure(cfg->dev, &uart_cfg) != 0) {
|
||||||
LOG_ERR("Failed to configure UART");
|
LOG_ERR("Failed to configure UART");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baudrate <= 38400) {
|
if (baudrate <= 38400) {
|
||||||
ctx->rtu_timeout = (numof_bits * if_delay_max) / baudrate;
|
cfg->rtu_timeout = (numof_bits * if_delay_max) / baudrate;
|
||||||
} else {
|
} else {
|
||||||
ctx->rtu_timeout = (numof_bits * if_delay_max) / 38400;
|
cfg->rtu_timeout = (numof_bits * if_delay_max) / 38400;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configure_gpio(ctx) != 0) {
|
if (configure_gpio(ctx) != 0) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_irq_callback_user_data_set(ctx->dev, uart_cb_handler, ctx);
|
cfg->uart_buf_ctr = 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);
|
modbus_serial_rx_on(ctx);
|
||||||
|
|
||||||
ctx->mode = ascii_mode ? MODBUS_MODE_ASCII : MODBUS_MODE_RTU;
|
ctx->mode = ascii_mode ? MODBUS_MODE_ASCII : MODBUS_MODE_RTU;
|
||||||
k_timer_init(&ctx->rtu_timer, rtu_tmr_handler, NULL);
|
k_timer_init(&cfg->rtu_timer, rtu_tmr_handler, NULL);
|
||||||
k_timer_user_data_set(&ctx->rtu_timer, ctx);
|
k_timer_user_data_set(&cfg->rtu_timer, ctx);
|
||||||
LOG_INF("RTU timeout %u us", ctx->rtu_timeout);
|
LOG_INF("RTU timeout %u us", cfg->rtu_timeout);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -576,6 +598,5 @@ void modbus_serial_disable(struct modbus_context *ctx)
|
||||||
{
|
{
|
||||||
modbus_serial_tx_off(ctx);
|
modbus_serial_tx_off(ctx);
|
||||||
modbus_serial_rx_off(ctx);
|
modbus_serial_rx_off(ctx);
|
||||||
k_timer_stop(&ctx->rtu_timer);
|
k_timer_stop(&ctx->cfg->rtu_timer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue