123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- /*
- * Copyright (c) 2020 PHYTEC Messtechnik GmbH
- * Copyright (c) 2021 Nordic Semiconductor ASA
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /*
- * Client API in this file is based on mbm_core.c 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.
- */
- /**
- * @brief MODBUS transport protocol API
- * @defgroup modbus MODBUS
- * @ingroup io_interfaces
- * @{
- */
- #ifndef ZEPHYR_INCLUDE_MODBUS_H_
- #define ZEPHYR_INCLUDE_MODBUS_H_
- #include <drivers/uart.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- /** Length of MBAP Header */
- #define MODBUS_MBAP_LENGTH 7
- /** Length of MBAP Header plus function code */
- #define MODBUS_MBAP_AND_FC_LENGTH (MODBUS_MBAP_LENGTH + 1)
- /**
- * @brief Frame struct used internally and for raw ADU support.
- */
- struct modbus_adu {
- /** Transaction Identifier */
- uint16_t trans_id;
- /** Protocol Identifier */
- uint16_t proto_id;
- /** Length of the data only (not the length of unit ID + PDU) */
- uint16_t length;
- /** Unit Identifier */
- uint8_t unit_id;
- /** Function Code */
- uint8_t fc;
- /** Transaction Data */
- uint8_t data[CONFIG_MODBUS_BUFFER_SIZE - 4];
- /** RTU CRC */
- uint16_t crc;
- };
- /**
- * @brief Coil read (FC01)
- *
- * Sends a Modbus message to read the status of coils from a server.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Coil starting address
- * @param coil_tbl Pointer to an array of bytes containing the value
- * of the coils read.
- * The format is:
- *
- * MSB LSB
- * B7 B6 B5 B4 B3 B2 B1 B0
- * -------------------------------------
- * coil_tbl[0] #8 #7 #1
- * coil_tbl[1] #16 #15 #9
- * :
- * :
- *
- * Note that the array that will be receiving the coil
- * values must be greater than or equal to:
- * (num_coils - 1) / 8 + 1
- * @param num_coils Quantity of coils to read
- *
- * @retval 0 If the function was successful
- */
- int modbus_read_coils(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- uint8_t *const coil_tbl,
- const uint16_t num_coils);
- /**
- * @brief Read discrete inputs (FC02)
- *
- * Sends a Modbus message to read the status of discrete inputs from
- * a server.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Discrete input starting address
- * @param di_tbl Pointer to an array that will receive the state
- * of the discrete inputs.
- * The format of the array is as follows:
- *
- * MSB LSB
- * B7 B6 B5 B4 B3 B2 B1 B0
- * -------------------------------------
- * di_tbl[0] #8 #7 #1
- * di_tbl[1] #16 #15 #9
- * :
- * :
- *
- * Note that the array that will be receiving the discrete
- * input values must be greater than or equal to:
- * (num_di - 1) / 8 + 1
- * @param num_di Quantity of discrete inputs to read
- *
- * @retval 0 If the function was successful
- */
- int modbus_read_dinputs(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- uint8_t *const di_tbl,
- const uint16_t num_di);
- /**
- * @brief Read holding registers (FC03)
- *
- * Sends a Modbus message to read the value of holding registers
- * from a server.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Register starting address
- * @param reg_buf Is a pointer to an array that will receive
- * the current values of the holding registers from
- * the server. The array pointed to by 'reg_buf' needs
- * to be able to hold at least 'num_regs' entries.
- * @param num_regs Quantity of registers to read
- *
- * @retval 0 If the function was successful
- */
- int modbus_read_holding_regs(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- uint16_t *const reg_buf,
- const uint16_t num_regs);
- /**
- * @brief Read input registers (FC04)
- *
- * Sends a Modbus message to read the value of input registers from
- * a server.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Register starting address
- * @param reg_buf Is a pointer to an array that will receive
- * the current value of the holding registers
- * from the server. The array pointed to by 'reg_buf'
- * needs to be able to hold at least 'num_regs' entries.
- * @param num_regs Quantity of registers to read
- *
- * @retval 0 If the function was successful
- */
- int modbus_read_input_regs(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- uint16_t *const reg_buf,
- const uint16_t num_regs);
- /**
- * @brief Write single coil (FC05)
- *
- * Sends a Modbus message to write the value of single coil to a server.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param coil_addr Coils starting address
- * @param coil_state Is the desired state of the coil
- *
- * @retval 0 If the function was successful
- */
- int modbus_write_coil(const int iface,
- const uint8_t unit_id,
- const uint16_t coil_addr,
- const bool coil_state);
- /**
- * @brief Write single holding register (FC06)
- *
- * Sends a Modbus message to write the value of single holding register
- * to a server unit.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Coils starting address
- * @param reg_val Desired value of the holding register
- *
- * @retval 0 If the function was successful
- */
- int modbus_write_holding_reg(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- const uint16_t reg_val);
- /**
- * @brief Read diagnostic (FC08)
- *
- * Sends a Modbus message to perform a diagnostic function of a server unit.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param sfunc Diagnostic sub-function code
- * @param data Sub-function data
- * @param data_out Pointer to the data value
- *
- * @retval 0 If the function was successful
- */
- int modbus_request_diagnostic(const int iface,
- const uint8_t unit_id,
- const uint16_t sfunc,
- const uint16_t data,
- uint16_t *const data_out);
- /**
- * @brief Write coils (FC15)
- *
- * Sends a Modbus message to write to coils on a server unit.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Coils starting address
- * @param coil_tbl Pointer to an array of bytes containing the value
- * of the coils to write.
- * The format is:
- *
- * MSB LSB
- * B7 B6 B5 B4 B3 B2 B1 B0
- * -------------------------------------
- * coil_tbl[0] #8 #7 #1
- * coil_tbl[1] #16 #15 #9
- * :
- * :
- *
- * Note that the array that will be receiving the coil
- * values must be greater than or equal to:
- * (num_coils - 1) / 8 + 1
- * @param num_coils Quantity of coils to write
- *
- * @retval 0 If the function was successful
- */
- int modbus_write_coils(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- uint8_t *const coil_tbl,
- const uint16_t num_coils);
- /**
- * @brief Write holding registers (FC16)
- *
- * Sends a Modbus message to write to integer holding registers
- * to a server unit.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Register starting address
- * @param reg_buf Is a pointer to an array containing
- * the value of the holding registers to write.
- * Note that the array containing the register values must
- * be greater than or equal to 'num_regs'
- * @param num_regs Quantity of registers to write
- *
- * @retval 0 If the function was successful
- */
- int modbus_write_holding_regs(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- uint16_t *const reg_buf,
- const uint16_t num_regs);
- /**
- * @brief Read floating-point holding registers (FC03)
- *
- * Sends a Modbus message to read the value of floating-point
- * holding registers from a server unit.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Register starting address
- * @param reg_buf Is a pointer to an array that will receive
- * the current values of the holding registers from
- * the server. The array pointed to by 'reg_buf' needs
- * to be able to hold at least 'num_regs' entries.
- * @param num_regs Quantity of registers to read
- *
- * @retval 0 If the function was successful
- */
- int modbus_read_holding_regs_fp(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- float *const reg_buf,
- const uint16_t num_regs);
- /**
- * @brief Write floating-point holding registers (FC16)
- *
- * Sends a Modbus message to write to floating-point holding registers
- * to a server unit.
- *
- * @param iface Modbus interface index
- * @param unit_id Modbus unit ID of the server
- * @param start_addr Register starting address
- * @param reg_buf Is a pointer to an array containing
- * the value of the holding registers to write.
- * Note that the array containing the register values must
- * be greater than or equal to 'num_regs'
- * @param num_regs Quantity of registers to write
- *
- * @retval 0 If the function was successful
- */
- int modbus_write_holding_regs_fp(const int iface,
- const uint8_t unit_id,
- const uint16_t start_addr,
- float *const reg_buf,
- const uint16_t num_regs);
- /** Modbus Server User Callback structure */
- struct modbus_user_callbacks {
- /** Coil read callback */
- int (*coil_rd)(uint16_t addr, bool *state);
- /** Coil write callback */
- int (*coil_wr)(uint16_t addr, bool state);
- /** Discrete Input read callback */
- int (*discrete_input_rd)(uint16_t addr, bool *state);
- /** Input Register read callback */
- int (*input_reg_rd)(uint16_t addr, uint16_t *reg);
- /** Floating Point Input Register read callback */
- int (*input_reg_rd_fp)(uint16_t addr, float *reg);
- /** Holding Register read callback */
- int (*holding_reg_rd)(uint16_t addr, uint16_t *reg);
- /** Holding Register write callback */
- int (*holding_reg_wr)(uint16_t addr, uint16_t reg);
- /** Floating Point Holding Register read callback */
- int (*holding_reg_rd_fp)(uint16_t addr, float *reg);
- /** Floating Point Holding Register write callback */
- int (*holding_reg_wr_fp)(uint16_t addr, float reg);
- };
- /**
- * @brief Get Modbus interface index according to interface name
- *
- * If there is more than one interface, it can be used to clearly
- * identify interfaces in the application.
- *
- * @param iface_name Modbus interface name
- *
- * @retval Modbus interface index or negative error value.
- */
- int modbus_iface_get_by_name(const char *iface_name);
- /**
- * @brief ADU raw callback function signature
- *
- * @param iface Modbus RTU interface index
- * @param adu Pointer to the RAW ADU struct to send
- *
- * @retval 0 If transfer was successful
- */
- typedef int (*modbus_raw_cb_t)(const int iface, const struct modbus_adu *adu);
- /**
- * @brief Modbus interface mode
- */
- enum modbus_mode {
- /** Modbus over serial line RTU mode */
- MODBUS_MODE_RTU,
- /** Modbus over serial line ASCII mode */
- MODBUS_MODE_ASCII,
- /** Modbus raw ADU mode */
- MODBUS_MODE_RAW,
- };
- /**
- * @brief Modbus serial line parameter
- */
- struct modbus_serial_param {
- /** Baudrate of the serial line */
- uint32_t baud;
- /** parity UART's parity setting:
- * UART_CFG_PARITY_NONE,
- * UART_CFG_PARITY_EVEN,
- * UART_CFG_PARITY_ODD
- */
- enum uart_config_parity parity;
- };
- /**
- * @brief Modbus server parameter
- */
- struct modbus_server_param {
- /** Pointer to the User Callback structure */
- struct modbus_user_callbacks *user_cb;
- /** Modbus unit ID of the server */
- uint8_t unit_id;
- };
- /**
- * @brief User parameter structure to configure Modbus interfase
- * as client or server.
- */
- struct modbus_iface_param {
- /** Mode of the interface */
- enum modbus_mode mode;
- union {
- struct modbus_server_param server;
- /** Amount of time client will wait for
- * a response from the server.
- */
- uint32_t rx_timeout;
- };
- union {
- /** Serial support parameter of the interface */
- struct modbus_serial_param serial;
- /** Pointer to raw ADU callback function */
- modbus_raw_cb_t raw_tx_cb;
- };
- };
- /**
- * @brief Configure Modbus Interface as raw ADU server
- *
- * @param iface Modbus RTU interface index
- * @param param Configuration parameter of the server interface
- *
- * @retval 0 If the function was successful
- */
- int modbus_init_server(const int iface, struct modbus_iface_param param);
- /**
- * @brief Configure Modbus Interface as raw ADU client
- *
- * @param iface Modbus RTU interface index
- * @param param Configuration parameter of the client interface
- *
- * @retval 0 If the function was successful
- */
- int modbus_init_client(const int iface, struct modbus_iface_param param);
- /**
- * @brief Disable Modbus Interface
- *
- * This function is called to disable Modbus interface.
- *
- * @param iface Modbus interface index
- *
- * @retval 0 If the function was successful
- */
- int modbus_disable(const uint8_t iface);
- /**
- * @brief Submit raw ADU
- *
- * @param iface Modbus RTU interface index
- * @param adu Pointer to the RAW ADU struct that is received
- *
- * @retval 0 If transfer was successful
- */
- int modbus_raw_submit_rx(const int iface, const struct modbus_adu *adu);
- /**
- * @brief Put MBAP header into a buffer
- *
- * @param adu Pointer to the RAW ADU struct
- * @param header Pointer to the buffer in which MBAP header
- * will be placed.
- *
- * @retval 0 If transfer was successful
- */
- void modbus_raw_put_header(const struct modbus_adu *adu, uint8_t *header);
- /**
- * @brief Get MBAP header from a buffer
- *
- * @param adu Pointer to the RAW ADU struct
- * @param header Pointer to the buffer containing MBAP header
- *
- * @retval 0 If transfer was successful
- */
- void modbus_raw_get_header(struct modbus_adu *adu, const uint8_t *header);
- /**
- * @brief Set Server Device Failure exception
- *
- * This function modifies ADU passed by the pointer.
- *
- * @param adu Pointer to the RAW ADU struct
- */
- void modbus_raw_set_server_failure(struct modbus_adu *adu);
- /**
- * @brief Use interface as backend to send and receive ADU
- *
- * This function overwrites ADU passed by the pointer and generates
- * exception responses if backend interface is misconfigured or
- * target device is unreachable.
- *
- * @param iface Modbus client interface index
- * @param adu Pointer to the RAW ADU struct
- *
- * @retval 0 If transfer was successful
- */
- int modbus_raw_backend_txn(const int iface, struct modbus_adu *adu);
- #ifdef __cplusplus
- }
- #endif
- /**
- * @}
- */
- #endif /* ZEPHYR_INCLUDE_MODBUS_H_ */
|