forked from espressif/esp-modbus
224 lines
8.6 KiB
C
224 lines
8.6 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <sys/queue.h>
|
|
|
|
#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 |