/* * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include #include #include "mb_config.h" #include "mb_frame.h" #include "mb_types.h" #include "port_common.h" #include "mb_callbacks.h" #include "mb_port_types.h" #include "esp_log.h" #include "sdkconfig.h" /* Common definitions */ #ifdef __cplusplus extern "C" { #endif #if __has_include("esp_check.h") #include "esp_check.h" #define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) ESP_RETURN_ON_FALSE(a, err_code, tag, format __VA_OPT__(,) __VA_ARGS__) #define MB_GOTO_ON_ERROR(x, goto_tag, log_tag, format, ...) ESP_GOTO_ON_ERROR(x, goto_tag, log_tag, format __VA_OPT__(,) __VA_ARGS__) #define MB_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) ESP_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format __VA_OPT__(,) __VA_ARGS__) #else // if cannot include esp_check then use custom check macro #define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) do { \ if (!(a)) { \ ESP_LOGE(tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \ return err_code; \ } \ } while(0) #define MB_GOTO_ON_ERROR(x, goto_tag, log_tag, format, ...) do { \ esp_err_t err_rc_ = (x); \ if (err_rc_ != ESP_OK) { \ ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \ ret = err_rc_; \ goto goto_tag; \ } \ } while(0) #define MB_GOTO_ON_FALSE(a, err_code, goto_tag, log_tag, format, ...) do { \ (void)log_tag; \ if (!(a)) { \ ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \ ret = (err_code); \ goto goto_tag; \ } \ } while (0) #endif #define MB_CAT_BUF_SIZE (100) #define MB_HANDLER_UNLOCK_TICKS (pdMS_TO_TICKS(5000)) #define SEMA_SECTION(sema, tout) for (int st = (int)xSemaphoreTake(sema, tout); (st > 0); xSemaphoreGive(sema), st = -1) #define MB_STR_CAT(pref, message) (__extension__( \ { \ char buf##__FUNCTION__##__LINE__[MB_CAT_BUF_SIZE]; \ strncpy(&(buf##__FUNCTION__##__LINE__)[0], pref, (MB_CAT_BUF_SIZE - 1)); \ strncat((buf##__FUNCTION__##__LINE__), message, (MB_CAT_BUF_SIZE - 1)); \ (&((buf##__FUNCTION__##__LINE__)[0])); \ } \ )) #define MB_OBJ_FMT "%p" #define MB_GET_OBJ_CTX(pinst, type, base) (__extension__( \ { \ assert(pinst); \ ((type *)__containerof(pinst, type, base)); \ } \ )) #define MB_OBJ(pinst) (__extension__( \ { \ assert(pinst); \ ((typeof(pinst))(pinst)); \ } \ )) #define MB_OBJ_PARENT(pinst) (__extension__( \ { \ assert(pinst); \ (((obj_descr_t*)(pinst))->parent); \ } \ )) #define MB_BASE2PORT(pinst) (__extension__( \ { \ assert(pinst); \ assert(((mb_base_t *)pinst)->port_obj); \ (((mb_base_t *)pinst)->port_obj); \ } \ )) /** * @brief Modbus function handlers entry */ typedef struct mb_command_entry_s { uint8_t func_code; /*!< function code */ mb_fn_handler_fp handler; /*!< handler function pointer */ LIST_ENTRY(mb_command_entry_s) entries; /*!< command handler entry */ } mb_command_entry_t; typedef LIST_HEAD(handler_head, mb_command_entry_s) handler_head_t; typedef struct mb_handler_descriptor_s { SemaphoreHandle_t sema; void* instance; handler_head_t head; uint16_t count; } handler_descriptor_t; typedef struct mb_base_t mb_base_t; typedef struct mb_trans_base_t mb_trans_base_t; typedef struct mb_port_base_t mb_port_base_t; typedef struct _obj_descr obj_descr_t; typedef mb_err_enum_t (*mb_delete_fp)(mb_base_t *inst); typedef mb_err_enum_t (*mb_enable_fp)(mb_base_t *inst); typedef mb_err_enum_t (*mb_disable_fp)(mb_base_t *inst); typedef mb_err_enum_t (*mb_poll_fp)(mb_base_t *inst); typedef void (*mb_set_addr_fp)(mb_base_t *inst, uint8_t dest_addr); typedef uint8_t (*mb_get_addr_fp)(mb_base_t *inst); typedef void (*mb_set_send_len_fp)(mb_base_t *inst, uint16_t len); typedef uint16_t (*mb_get_send_len_fp)(mb_base_t *inst); typedef void (*mb_get_send_buf_fp)(mb_base_t *inst, uint8_t **pbuf); typedef enum { STATE_ENABLED, STATE_DISABLED, STATE_NOT_INITIALIZED } mb_state_enum_t; struct mb_base_t { obj_descr_t descr; _lock_t lock; // base object lock mb_trans_base_t *transp_obj; mb_port_base_t *port_obj; #if MB_FUNC_OTHER_REP_SLAVEID_ENABLED uint8_t *pobj_id; uint16_t obj_id_len; uint8_t obj_id_chunks; #endif mb_delete_fp delete; mb_enable_fp enable; mb_disable_fp disable; mb_poll_fp poll; mb_set_addr_fp set_dest_addr; mb_get_addr_fp get_dest_addr; mb_set_send_len_fp set_send_len; mb_get_send_len_fp get_send_len; mb_get_send_buf_fp get_send_buf; mb_rw_callbacks_t rw_cbs; }; // Helper functions for command handlers registration mb_err_enum_t mb_set_handler(handler_descriptor_t *pdescriptor, uint8_t func_code, mb_fn_handler_fp phandler); mb_err_enum_t mb_get_handler(handler_descriptor_t *pdescriptor, uint8_t func_code, mb_fn_handler_fp *phandler); mb_err_enum_t mb_delete_handler(handler_descriptor_t *pdescriptor, uint8_t func_code); mb_err_enum_t mb_delete_command_handlers(handler_descriptor_t *pdescriptor); #if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN) typedef struct port_serial_opts_s mb_serial_opts_t; mb_err_enum_t mbs_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj); mb_err_enum_t mbs_ascii_create(mb_serial_opts_t *ser_opts, void **in_out_obj); #endif #if (CONFIG_FMB_COMM_MODE_TCP_EN) typedef struct port_tcp_opts_s mb_tcp_opts_t; mb_err_enum_t mbs_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj); #endif mb_err_enum_t mbs_delete(mb_base_t *inst); mb_err_enum_t mbs_enable(mb_base_t *inst); mb_err_enum_t mbs_disable(mb_base_t *inst); mb_err_enum_t mbs_poll(mb_base_t *inst); #if (CONFIG_FMB_COMM_MODE_RTU_EN || CONFIG_FMB_COMM_MODE_ASCII_EN) mb_err_enum_t mbm_rtu_create(mb_serial_opts_t *ser_opts, void **in_out_obj); mb_err_enum_t mbm_ascii_create(mb_serial_opts_t *ser_opts, void **in_out_obj); #endif #if (CONFIG_FMB_COMM_MODE_TCP_EN) mb_err_enum_t mbm_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj); #endif mb_err_enum_t mbm_delete(mb_base_t *inst); mb_err_enum_t mbm_enable(mb_base_t *inst); mb_err_enum_t mbm_disable(mb_base_t *inst); mb_err_enum_t mbm_poll(mb_base_t *inst); #ifdef __cplusplus } #endif