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 exception codes */ 59 #define MODBUS_EXC_NONE 0 60 #define MODBUS_EXC_ILLEGAL_FC 1 61 #define MODBUS_EXC_ILLEGAL_DATA_ADDR 2 62 #define MODBUS_EXC_ILLEGAL_DATA_VAL 3 63 #define MODBUS_EXC_SERVER_DEVICE_FAILURE 4 64 #define MODBUS_EXC_ACK 5 65 #define MODBUS_EXC_SERVER_DEVICE_BUSY 6 66 #define MODBUS_EXC_MEM_PARITY_ERROR 8 67 #define MODBUS_EXC_GW_PATH_UNAVAILABLE 10 68 #define MODBUS_EXC_GW_TARGET_FAILED_TO_RESP 11 69 70 /* Modbus RTU (ASCII) constants */ 71 #define MODBUS_COIL_OFF_CODE 0x0000 72 #define MODBUS_COIL_ON_CODE 0xFF00 73 #define MODBUS_RTU_MIN_MSG_SIZE 4 74 #define MODBUS_CRC16_POLY 0xA001 75 #define MODBUS_ASCII_MIN_MSG_SIZE 11 76 #define MODBUS_ASCII_START_FRAME_CHAR ':' 77 #define MODBUS_ASCII_END_FRAME_CHAR1 '\r' 78 #define MODBUS_ASCII_END_FRAME_CHAR2 '\n' 79 80 /* Modbus ADU constants */ 81 #define MODBUS_ADU_PROTO_ID 0x0000 82 83 struct modbus_serial_config { 84 /* UART device */ 85 const struct device *dev; 86 /* RTU timeout (maximum inter-frame delay) */ 87 uint32_t rtu_timeout; 88 /* Pointer to current position in buffer */ 89 uint8_t *uart_buf_ptr; 90 /* Pointer to driver enable (DE) pin config */ 91 struct gpio_dt_spec *de; 92 /* Pointer to receiver enable (nRE) pin config */ 93 struct gpio_dt_spec *re; 94 /* RTU timer to detect frame end point */ 95 struct k_timer rtu_timer; 96 /* Number of bytes received or to send */ 97 uint16_t uart_buf_ctr; 98 /* Storage of received characters or characters to send */ 99 uint8_t uart_buf[CONFIG_MODBUS_BUFFER_SIZE]; 100 }; 101 102 #define MODBUS_STATE_CONFIGURED 0 103 104 struct modbus_context { 105 /* Interface name */ 106 const char *iface_name; 107 union { 108 /* Serial line configuration */ 109 struct modbus_serial_config *cfg; 110 /* RAW TX callback */ 111 struct modbus_raw_cb rawcb; 112 }; 113 /* MODBUS mode */ 114 enum modbus_mode mode; 115 /* True if interface is configured as client */ 116 bool client; 117 /* Amount of time client is willing to wait for response from server */ 118 uint32_t rxwait_to; 119 /* Pointer to user server callbacks */ 120 struct modbus_user_callbacks *mbs_user_cb; 121 /* Interface state */ 122 atomic_t state; 123 124 /* Client's mutually exclusive access */ 125 struct k_mutex iface_lock; 126 /* Wait for response semaphore */ 127 struct k_sem client_wait_sem; 128 /* Server work item */ 129 struct k_work server_work; 130 /* Received frame */ 131 struct modbus_adu rx_adu; 132 /* Frame to transmit */ 133 struct modbus_adu tx_adu; 134 135 /* Records error from frame reception, e.g. CRC error */ 136 int rx_adu_err; 137 138 #ifdef CONFIG_MODBUS_FC08_DIAGNOSTIC 139 uint16_t mbs_msg_ctr; 140 uint16_t mbs_crc_err_ctr; 141 uint16_t mbs_except_ctr; 142 uint16_t mbs_server_msg_ctr; 143 uint16_t mbs_noresp_ctr; 144 #endif 145 /* Unit ID */ 146 uint8_t unit_id; 147 148 }; 149 150 /** 151 * @brief Get Modbus interface context. 152 * 153 * @param ctx Modbus interface context 154 * 155 * @retval Pointer to interface context or NULL 156 * if interface not available or not configured; 157 */ 158 struct modbus_context *modbus_get_context(const uint8_t iface); 159 160 /** 161 * @brief Get Modbus interface index. 162 * 163 * @param ctx Pointer to Modbus interface context 164 * 165 * @retval Interface index or negative error value. 166 */ 167 int modbus_iface_get_by_ctx(const struct modbus_context *ctx); 168 169 /** 170 * @brief Send ADU. 171 * 172 * @param ctx Modbus interface context 173 */ 174 void modbus_tx_adu(struct modbus_context *ctx); 175 176 /** 177 * @brief Send ADU and wait certain time for response. 178 * 179 * @param ctx Modbus interface context 180 * 181 * @retval 0 If the function was successful, 182 * -ENOTSUP if Modbus mode is not supported, 183 * -ETIMEDOUT on timeout, 184 * -EMSGSIZE on length error, 185 * -EIO on CRC error. 186 */ 187 int modbus_tx_wait_rx_adu(struct modbus_context *ctx); 188 189 /** 190 * @brief Let server handle the received ADU. 191 * 192 * @param ctx Modbus interface context 193 * 194 * @retval True if the server has prepared a response ADU 195 * that should be sent. 196 */ 197 bool modbus_server_handler(struct modbus_context *ctx); 198 199 /** 200 * @brief Reset server stats. 201 * 202 * @param ctx Modbus interface context 203 */ 204 void modbus_reset_stats(struct modbus_context *ctx); 205 206 /** 207 * @brief Disable serial line reception. 208 * 209 * @param ctx Modbus interface context 210 */ 211 void modbus_serial_rx_disable(struct modbus_context *ctx); 212 213 /** 214 * @brief Enable serial line reception. 215 * 216 * @param ctx Modbus interface context 217 */ 218 void modbus_serial_rx_enable(struct modbus_context *ctx); 219 220 /** 221 * @brief Assemble ADU from serial line RX buffer 222 * 223 * @param ctx Modbus interface context 224 * 225 * @retval 0 If the function was successful, 226 * -ENOTSUP if serial line mode is not supported, 227 * -EMSGSIZE on length error, 228 * -EIO on CRC error. 229 */ 230 int modbus_serial_rx_adu(struct modbus_context *ctx); 231 232 /** 233 * @brief Assemble ADU from serial line RX buffer 234 * 235 * @param ctx Modbus interface context 236 * 237 * @retval 0 If the function was successful, 238 * -ENOTSUP if serial line mode is not supported. 239 */ 240 int modbus_serial_tx_adu(struct modbus_context *ctx); 241 242 /** 243 * @brief Initialize serial line support. 244 * 245 * @param ctx Modbus interface context 246 * @param param Configuration parameter of the interface 247 * 248 * @retval 0 If the function was successful. 249 */ 250 int modbus_serial_init(struct modbus_context *ctx, 251 struct modbus_iface_param param); 252 253 /** 254 * @brief Disable serial line support. 255 * 256 * @param ctx Modbus interface context 257 */ 258 void modbus_serial_disable(struct modbus_context *ctx); 259 260 int modbus_raw_rx_adu(struct modbus_context *ctx); 261 int modbus_raw_tx_adu(struct modbus_context *ctx); 262 int modbus_raw_init(struct modbus_context *ctx, 263 struct modbus_iface_param param); 264 265 #endif /* ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ */ 266