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 92 struct modbus_context { 93 /* Interface name */ 94 const char *iface_name; 95 union { 96 /* Serial line configuration */ 97 struct modbus_serial_config *cfg; 98 /* RAW TX callback */ 99 struct modbus_raw_cb rawcb; 100 }; 101 /* MODBUS mode */ 102 enum modbus_mode mode; 103 /* True if interface is configured as client */ 104 bool client; 105 /* Amount of time client is willing to wait for response from server */ 106 uint32_t rxwait_to; 107 /* Pointer to user server callbacks */ 108 struct modbus_user_callbacks *mbs_user_cb; 109 /* Interface state */ 110 atomic_t state; 111 112 /* Client's mutually exclusive access */ 113 struct k_mutex iface_lock; 114 /* Wait for response semaphore */ 115 struct k_sem client_wait_sem; 116 /* Server work item */ 117 struct k_work server_work; 118 /* Received frame */ 119 struct modbus_adu rx_adu; 120 /* Frame to transmit */ 121 struct modbus_adu tx_adu; 122 123 /* Records error from frame reception, e.g. CRC error */ 124 int rx_adu_err; 125 126 #ifdef CONFIG_MODBUS_FC08_DIAGNOSTIC 127 uint16_t mbs_msg_ctr; 128 uint16_t mbs_crc_err_ctr; 129 uint16_t mbs_except_ctr; 130 uint16_t mbs_server_msg_ctr; 131 uint16_t mbs_noresp_ctr; 132 #endif 133 /* A linked list of function code, handler pairs */ 134 sys_slist_t user_defined_cbs; 135 /* Unit ID */ 136 uint8_t unit_id; 137 138 }; 139 140 /** 141 * @brief Get Modbus interface context. 142 * 143 * @param ctx Modbus interface context 144 * 145 * @retval Pointer to interface context or NULL 146 * if interface not available or not configured; 147 */ 148 struct modbus_context *modbus_get_context(const uint8_t iface); 149 150 /** 151 * @brief Get Modbus interface index. 152 * 153 * @param ctx Pointer to Modbus interface context 154 * 155 * @retval Interface index or negative error value. 156 */ 157 int modbus_iface_get_by_ctx(const struct modbus_context *ctx); 158 159 /** 160 * @brief Send ADU. 161 * 162 * @param ctx Modbus interface context 163 */ 164 void modbus_tx_adu(struct modbus_context *ctx); 165 166 /** 167 * @brief Send ADU and wait certain time for response. 168 * 169 * @param ctx Modbus interface context 170 * 171 * @retval 0 If the function was successful, 172 * -ENOTSUP if Modbus mode is not supported, 173 * -ETIMEDOUT on timeout, 174 * -EMSGSIZE on length error, 175 * -EIO on CRC error. 176 */ 177 int modbus_tx_wait_rx_adu(struct modbus_context *ctx); 178 179 /** 180 * @brief Let server handle the received ADU. 181 * 182 * @param ctx Modbus interface context 183 * 184 * @retval True if the server has prepared a response ADU 185 * that should be sent. 186 */ 187 bool modbus_server_handler(struct modbus_context *ctx); 188 189 /** 190 * @brief Reset server stats. 191 * 192 * @param ctx Modbus interface context 193 */ 194 void modbus_reset_stats(struct modbus_context *ctx); 195 196 /** 197 * @brief Disable serial line reception. 198 * 199 * @param ctx Modbus interface context 200 */ 201 void modbus_serial_rx_disable(struct modbus_context *ctx); 202 203 /** 204 * @brief Enable serial line reception. 205 * 206 * @param ctx Modbus interface context 207 */ 208 void modbus_serial_rx_enable(struct modbus_context *ctx); 209 210 /** 211 * @brief Assemble ADU from serial line RX buffer 212 * 213 * @param ctx Modbus interface context 214 * 215 * @retval 0 If the function was successful, 216 * -ENOTSUP if serial line mode is not supported, 217 * -EMSGSIZE on length error, 218 * -EIO on CRC error. 219 */ 220 int modbus_serial_rx_adu(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 */ 230 int modbus_serial_tx_adu(struct modbus_context *ctx); 231 232 /** 233 * @brief Initialize serial line support. 234 * 235 * @param ctx Modbus interface context 236 * @param param Configuration parameter of the interface 237 * 238 * @retval 0 If the function was successful. 239 */ 240 int modbus_serial_init(struct modbus_context *ctx, 241 struct modbus_iface_param param); 242 243 /** 244 * @brief Disable serial line support. 245 * 246 * @param ctx Modbus interface context 247 */ 248 void modbus_serial_disable(struct modbus_context *ctx); 249 250 int modbus_raw_rx_adu(struct modbus_context *ctx); 251 int modbus_raw_tx_adu(struct modbus_context *ctx); 252 int modbus_raw_init(struct modbus_context *ctx, 253 struct modbus_iface_param param); 254 255 #endif /* ZEPHYR_INCLUDE_MODBUS_INTERNAL_H_ */ 256