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