1 /* 2 * Copyright (c) 2020 PHYTEC Messtechnik GmbH 3 * Copyright (c) 2021 Nordic Semiconductor ASA 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 8 /* 9 * Parts of this file are based on mb.h from uC/Modbus Stack. 10 * 11 * uC/Modbus 12 * The Embedded Modbus Stack 13 * 14 * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com 15 * 16 * SPDX-License-Identifier: Apache-2.0 17 * 18 * This software is subject to an open source license and is distributed by 19 * Silicon Laboratories Inc. pursuant to the terms of the Apache License, 20 * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0. 21 */ 22 23 #ifndef ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ 24 #define ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ 25 26 #include <zephyr/kernel.h> 27 #include <zephyr/drivers/gpio.h> 28 #include <zephyr/modbus/modbus.h> 29 30 #ifdef CONFIG_MODBUS_FP_EXTENSIONS 31 #define MODBUS_FP_EXTENSIONS_ADDR 5000 32 #else 33 #define MODBUS_FP_EXTENSIONS_ADDR UINT16_MAX 34 #endif 35 36 #define MODBUS_RTU_MTU 256 37 38 /* Modbus function codes */ 39 #define MODBUS_FC01_COIL_RD 1 40 #define MODBUS_FC02_DI_RD 2 41 #define MODBUS_FC03_HOLDING_REG_RD 3 42 #define MODBUS_FC04_IN_REG_RD 4 43 #define MODBUS_FC05_COIL_WR 5 44 #define MODBUS_FC06_HOLDING_REG_WR 6 45 #define MODBUS_FC08_DIAGNOSTICS 8 46 #define MODBUS_FC15_COILS_WR 15 47 #define MODBUS_FC16_HOLDING_REGS_WR 16 48 49 /* Diagnostic sub-function codes */ 50 #define MODBUS_FC08_SUBF_QUERY 0 51 #define MODBUS_FC08_SUBF_CLR_CTR 10 52 #define MODBUS_FC08_SUBF_BUS_MSG_CTR 11 53 #define MODBUS_FC08_SUBF_BUS_CRC_CTR 12 54 #define MODBUS_FC08_SUBF_BUS_EXCEPT_CTR 13 55 #define MODBUS_FC08_SUBF_SERVER_MSG_CTR 14 56 #define MODBUS_FC08_SUBF_SERVER_NO_RESP_CTR 15 57 58 /* Modbus RTU (ASCII) constants */ 59 #define MODBUS_COIL_OFF_CODE 0x0000 60 #define MODBUS_COIL_ON_CODE 0xFF00 61 #define MODBUS_RTU_MIN_MSG_SIZE 4 62 #define MODBUS_CRC16_POLY 0xA001 63 #define MODBUS_ASCII_MIN_MSG_SIZE 11 64 #define MODBUS_ASCII_START_FRAME_CHAR ':' 65 #define MODBUS_ASCII_END_FRAME_CHAR1 '\r' 66 #define MODBUS_ASCII_END_FRAME_CHAR2 '\n' 67 68 /* Modbus ADU constants */ 69 #define MODBUS_ADU_PROTO_ID 0x0000 70 71 struct modbus_serial_config { 72 /* UART device */ 73 const struct device *dev; 74 /* RTU timeout (maximum inter-frame delay) */ 75 uint32_t rtu_timeout; 76 /* Pointer to current position in buffer */ 77 uint8_t *uart_buf_ptr; 78 /* Pointer to driver enable (DE) pin config */ 79 struct gpio_dt_spec *de; 80 /* Pointer to receiver enable (nRE) pin config */ 81 struct gpio_dt_spec *re; 82 /* RTU timer to detect frame end point */ 83 struct k_timer rtu_timer; 84 /* Number of bytes received or to send */ 85 uint16_t uart_buf_ctr; 86 /* Storage of received characters or characters to send */ 87 uint8_t uart_buf[CONFIG_MODBUS_BUFFER_SIZE]; 88 }; 89 90 #define MODBUS_STATE_CONFIGURED 0 91 #define MODBUS_STATE_RX_ENABLED 1 92 93 struct modbus_context { 94 /* Interface name */ 95 const char *iface_name; 96 union { 97 /* Serial line configuration */ 98 struct modbus_serial_config *cfg; 99 /* RAW TX callback */ 100 struct modbus_raw_cb rawcb; 101 }; 102 /* MODBUS mode */ 103 enum modbus_mode mode; 104 /* True if interface is configured as client */ 105 bool client; 106 /* Amount of time client is willing to wait for response from server */ 107 uint32_t rxwait_to; 108 /* Pointer to user server callbacks */ 109 struct modbus_user_callbacks *mbs_user_cb; 110 /* Interface state */ 111 atomic_t state; 112 113 /* Client's mutually exclusive access */ 114 struct k_mutex iface_lock; 115 /* Wait for response semaphore */ 116 struct k_sem client_wait_sem; 117 /* Server work item */ 118 struct k_work server_work; 119 /* Received frame */ 120 struct modbus_adu rx_adu; 121 /* Frame to transmit */ 122 struct modbus_adu tx_adu; 123 124 /* Records error from frame reception, e.g. CRC error */ 125 int rx_adu_err; 126 127 #ifdef CONFIG_MODBUS_FC08_DIAGNOSTIC 128 uint16_t mbs_msg_ctr; 129 uint16_t mbs_crc_err_ctr; 130 uint16_t mbs_except_ctr; 131 uint16_t mbs_server_msg_ctr; 132 uint16_t mbs_noresp_ctr; 133 #endif 134 /* A linked list of function code, handler pairs */ 135 sys_slist_t user_defined_cbs; 136 /* Unit ID */ 137 uint8_t unit_id; 138 139 }; 140 141 /** 142 * @brief Get Modbus interface context. 143 * 144 * @param ctx Modbus interface context 145 * 146 * @retval Pointer to interface context or NULL 147 * if interface not available or not configured; 148 */ 149 struct modbus_context *modbus_get_context(const uint8_t iface); 150 151 /** 152 * @brief Get Modbus interface index. 153 * 154 * @param ctx Pointer to Modbus interface context 155 * 156 * @retval Interface index or negative error value. 157 */ 158 int modbus_iface_get_by_ctx(const struct modbus_context *ctx); 159 160 /** 161 * @brief Send ADU. 162 * 163 * @param ctx Modbus interface context 164 */ 165 void modbus_tx_adu(struct modbus_context *ctx); 166 167 /** 168 * @brief Send ADU and wait certain time for response. 169 * 170 * @param ctx Modbus interface context 171 * 172 * @retval 0 If the function was successful, 173 * -ENOTSUP if Modbus mode is not supported, 174 * -ETIMEDOUT on timeout, 175 * -EMSGSIZE on length error, 176 * -EIO on CRC error. 177 */ 178 int modbus_tx_wait_rx_adu(struct modbus_context *ctx); 179 180 /** 181 * @brief Let server handle the received ADU. 182 * 183 * @param ctx Modbus interface context 184 * 185 * @retval True if the server has prepared a response ADU 186 * that should be sent. 187 */ 188 bool modbus_server_handler(struct modbus_context *ctx); 189 190 /** 191 * @brief Reset server stats. 192 * 193 * @param ctx Modbus interface context 194 */ 195 void modbus_reset_stats(struct modbus_context *ctx); 196 197 /** 198 * @brief Disable serial line reception. 199 * 200 * @param ctx Modbus interface context 201 */ 202 void modbus_serial_rx_disable(struct modbus_context *ctx); 203 204 /** 205 * @brief Enable serial line reception. 206 * 207 * @param ctx Modbus interface context 208 */ 209 void modbus_serial_rx_enable(struct modbus_context *ctx); 210 211 /** 212 * @brief Assemble ADU from serial line RX buffer 213 * 214 * @param ctx Modbus interface context 215 * 216 * @retval 0 If the function was successful, 217 * -ENOTSUP if serial line mode is not supported, 218 * -EMSGSIZE on length error, 219 * -EIO on CRC error. 220 */ 221 int modbus_serial_rx_adu(struct modbus_context *ctx); 222 223 /** 224 * @brief Assemble ADU from serial line RX buffer 225 * 226 * @param ctx Modbus interface context 227 * 228 * @retval 0 If the function was successful, 229 * -ENOTSUP if serial line mode is not supported. 230 */ 231 int modbus_serial_tx_adu(struct modbus_context *ctx); 232 233 /** 234 * @brief Initialize serial line support. 235 * 236 * @param ctx Modbus interface context 237 * @param param Configuration parameter of the interface 238 * 239 * @retval 0 If the function was successful. 240 */ 241 int modbus_serial_init(struct modbus_context *ctx, 242 struct modbus_iface_param param); 243 244 /** 245 * @brief Disable serial line support. 246 * 247 * @param ctx Modbus interface context 248 */ 249 void modbus_serial_disable(struct modbus_context *ctx); 250 251 int modbus_raw_rx_adu(struct modbus_context *ctx); 252 int modbus_raw_tx_adu(struct modbus_context *ctx); 253 int modbus_raw_init(struct modbus_context *ctx, 254 struct modbus_iface_param param); 255 256 #endif /* ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ */ 257