You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
7.0 KiB
256 lines
7.0 KiB
/* |
|
* Copyright (c) 2020 PHYTEC Messtechnik GmbH |
|
* Copyright (c) 2021 Nordic Semiconductor ASA |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
/* |
|
* Parts of this file are based on mb.h from uC/Modbus Stack. |
|
* |
|
* uC/Modbus |
|
* The Embedded Modbus Stack |
|
* |
|
* Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
* |
|
* This software is subject to an open source license and is distributed by |
|
* Silicon Laboratories Inc. pursuant to the terms of the Apache License, |
|
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. |
|
*/ |
|
|
|
#ifndef ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ |
|
#define ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ |
|
|
|
#include <zephyr/kernel.h> |
|
#include <zephyr/drivers/gpio.h> |
|
#include <zephyr/modbus/modbus.h> |
|
|
|
#ifdef CONFIG_MODBUS_FP_EXTENSIONS |
|
#define MODBUS_FP_EXTENSIONS_ADDR 5000 |
|
#else |
|
#define MODBUS_FP_EXTENSIONS_ADDR UINT16_MAX |
|
#endif |
|
|
|
#define MODBUS_RTU_MTU 256 |
|
|
|
/* Modbus function codes */ |
|
#define MODBUS_FC01_COIL_RD 1 |
|
#define MODBUS_FC02_DI_RD 2 |
|
#define MODBUS_FC03_HOLDING_REG_RD 3 |
|
#define MODBUS_FC04_IN_REG_RD 4 |
|
#define MODBUS_FC05_COIL_WR 5 |
|
#define MODBUS_FC06_HOLDING_REG_WR 6 |
|
#define MODBUS_FC08_DIAGNOSTICS 8 |
|
#define MODBUS_FC15_COILS_WR 15 |
|
#define MODBUS_FC16_HOLDING_REGS_WR 16 |
|
|
|
/* Diagnostic sub-function codes */ |
|
#define MODBUS_FC08_SUBF_QUERY 0 |
|
#define MODBUS_FC08_SUBF_CLR_CTR 10 |
|
#define MODBUS_FC08_SUBF_BUS_MSG_CTR 11 |
|
#define MODBUS_FC08_SUBF_BUS_CRC_CTR 12 |
|
#define MODBUS_FC08_SUBF_BUS_EXCEPT_CTR 13 |
|
#define MODBUS_FC08_SUBF_SERVER_MSG_CTR 14 |
|
#define MODBUS_FC08_SUBF_SERVER_NO_RESP_CTR 15 |
|
|
|
/* Modbus RTU (ASCII) constants */ |
|
#define MODBUS_COIL_OFF_CODE 0x0000 |
|
#define MODBUS_COIL_ON_CODE 0xFF00 |
|
#define MODBUS_RTU_MIN_MSG_SIZE 4 |
|
#define MODBUS_CRC16_POLY 0xA001 |
|
#define MODBUS_ASCII_MIN_MSG_SIZE 11 |
|
#define MODBUS_ASCII_START_FRAME_CHAR ':' |
|
#define MODBUS_ASCII_END_FRAME_CHAR1 '\r' |
|
#define MODBUS_ASCII_END_FRAME_CHAR2 '\n' |
|
|
|
/* Modbus ADU constants */ |
|
#define MODBUS_ADU_PROTO_ID 0x0000 |
|
|
|
struct modbus_serial_config { |
|
/* UART device */ |
|
const struct device *dev; |
|
/* RTU timeout (maximum inter-frame delay) */ |
|
uint32_t rtu_timeout; |
|
/* Pointer to current position in buffer */ |
|
uint8_t *uart_buf_ptr; |
|
/* Pointer to driver enable (DE) pin config */ |
|
struct gpio_dt_spec *de; |
|
/* Pointer to receiver enable (nRE) pin config */ |
|
struct gpio_dt_spec *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 |
|
#define MODBUS_STATE_RX_ENABLED 1 |
|
|
|
struct modbus_context { |
|
/* Interface name */ |
|
const char *iface_name; |
|
union { |
|
/* Serial line configuration */ |
|
struct modbus_serial_config *cfg; |
|
/* RAW TX callback */ |
|
struct modbus_raw_cb rawcb; |
|
}; |
|
/* 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 */ |
|
struct k_mutex iface_lock; |
|
/* Wait for response semaphore */ |
|
struct k_sem client_wait_sem; |
|
/* Server work item */ |
|
struct k_work server_work; |
|
/* Received frame */ |
|
struct modbus_adu rx_adu; |
|
/* Frame to transmit */ |
|
struct modbus_adu tx_adu; |
|
|
|
/* Records error from frame reception, e.g. CRC error */ |
|
int rx_adu_err; |
|
|
|
#ifdef CONFIG_MODBUS_FC08_DIAGNOSTIC |
|
uint16_t mbs_msg_ctr; |
|
uint16_t mbs_crc_err_ctr; |
|
uint16_t mbs_except_ctr; |
|
uint16_t mbs_server_msg_ctr; |
|
uint16_t mbs_noresp_ctr; |
|
#endif |
|
/* A linked list of function code, handler pairs */ |
|
sys_slist_t user_defined_cbs; |
|
/* Unit ID */ |
|
uint8_t unit_id; |
|
|
|
}; |
|
|
|
/** |
|
* @brief Get Modbus interface context. |
|
* |
|
* @param ctx Modbus interface context |
|
* |
|
* @retval Pointer to interface context or NULL |
|
* if interface not available or not configured; |
|
*/ |
|
struct modbus_context *modbus_get_context(const uint8_t iface); |
|
|
|
/** |
|
* @brief Get Modbus interface index. |
|
* |
|
* @param ctx Pointer to Modbus interface context |
|
* |
|
* @retval Interface index or negative error value. |
|
*/ |
|
int modbus_iface_get_by_ctx(const struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Send ADU. |
|
* |
|
* @param ctx Modbus interface context |
|
*/ |
|
void modbus_tx_adu(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Send ADU and wait certain time for response. |
|
* |
|
* @param ctx Modbus interface context |
|
* |
|
* @retval 0 If the function was successful, |
|
* -ENOTSUP if Modbus mode is not supported, |
|
* -ETIMEDOUT on timeout, |
|
* -EMSGSIZE on length error, |
|
* -EIO on CRC error. |
|
*/ |
|
int modbus_tx_wait_rx_adu(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Let server handle the received ADU. |
|
* |
|
* @param ctx Modbus interface context |
|
* |
|
* @retval True if the server has prepared a response ADU |
|
* that should be sent. |
|
*/ |
|
bool modbus_server_handler(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Reset server stats. |
|
* |
|
* @param ctx Modbus interface context |
|
*/ |
|
void modbus_reset_stats(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Disable serial line reception. |
|
* |
|
* @param ctx Modbus interface context |
|
*/ |
|
void modbus_serial_rx_disable(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Enable serial line reception. |
|
* |
|
* @param ctx Modbus interface context |
|
*/ |
|
void modbus_serial_rx_enable(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Assemble ADU from serial line RX buffer |
|
* |
|
* @param ctx Modbus interface context |
|
* |
|
* @retval 0 If the function was successful, |
|
* -ENOTSUP if serial line mode is not supported, |
|
* -EMSGSIZE on length error, |
|
* -EIO on CRC error. |
|
*/ |
|
int modbus_serial_rx_adu(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Assemble ADU from serial line RX buffer |
|
* |
|
* @param ctx Modbus interface context |
|
* |
|
* @retval 0 If the function was successful, |
|
* -ENOTSUP if serial line mode is not supported. |
|
*/ |
|
int modbus_serial_tx_adu(struct modbus_context *ctx); |
|
|
|
/** |
|
* @brief Initialize serial line support. |
|
* |
|
* @param ctx Modbus interface context |
|
* @param param Configuration parameter of the interface |
|
* |
|
* @retval 0 If the function was successful. |
|
*/ |
|
int modbus_serial_init(struct modbus_context *ctx, |
|
struct modbus_iface_param param); |
|
|
|
/** |
|
* @brief Disable serial line support. |
|
* |
|
* @param ctx Modbus interface context |
|
*/ |
|
void modbus_serial_disable(struct modbus_context *ctx); |
|
|
|
int modbus_raw_rx_adu(struct modbus_context *ctx); |
|
int modbus_raw_tx_adu(struct modbus_context *ctx); |
|
int modbus_raw_init(struct modbus_context *ctx, |
|
struct modbus_iface_param param); |
|
|
|
#endif /* ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ */
|
|
|