Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions modbus/mb_controller/common/include/esp_modbus_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#pragma once
#include <inttypes.h>

#include "driver/uart.h" // for UART types
#include "sdkconfig.h"
Expand All @@ -13,20 +14,12 @@
#include "mb_endianness_utils.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#include "port_common.h"

#if __has_include("esp_check.h")
#include "esp_check.h"
#include "esp_log.h"

#include <inttypes.h>

#include "mb_port_types.h"

#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) ESP_RETURN_ON_FALSE(a, err_code, tag, format __VA_OPT__(,) __VA_ARGS__)

#else
Expand All @@ -42,6 +35,10 @@ extern "C" {

#endif

#ifdef __cplusplus
extern "C" {
#endif

#define MB_SLAVE_ADDR_PLACEHOLDER (0xFF)
#define MB_CONTROLLER_STACK_SIZE (CONFIG_FMB_CONTROLLER_STACK_SIZE) // Stack size for Modbus controller
#define MB_CONTROLLER_PRIORITY (CONFIG_FMB_PORT_TASK_PRIO - 1) // priority of MB controller task
Expand Down
14 changes: 6 additions & 8 deletions modbus/mb_objects/include/mb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

#include <inttypes.h>
#include "sdkconfig.h" // for KConfig options

#ifdef __cplusplus
extern "C" {
#endif

#if __has_include("esp_idf_version.h")
#include "esp_idf_version.h"
#endif

#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif

/* ----------------------- Defines ------------------------------------------*/
/*! \defgroup modbus_cfg Modbus Configuration
Expand Down Expand Up @@ -48,8 +46,8 @@ extern "C" {

#ifdef ESP_IDF_VERSION

#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0))
// Features supported from 4.4
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0))
// Features supported from v5.0
#define MB_TIMER_SUPPORTS_ISR_DISPATCH_METHOD 1
#endif

Expand Down
30 changes: 21 additions & 9 deletions modbus/mb_objects/include/mb_port_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,25 @@
*/
#pragma once

#include "stdatomic.h"
#include "mb_config.h"
#include "mb_types.h"

#ifdef __cplusplus
#if __has_include("esp_idf_version.h")
#include "esp_idf_version.h"
#define IS_OLD_IDF_VER (IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 0, 0))
#endif

// Workaround for atomics incompatibility issue under CPP.
#if defined(__cplusplus) && IS_OLD_IDF_VER
#include <atomic>
#define _Atomic(T) std::atomic<T>
#else
#include <stdatomic.h>
#endif



#if defined(__cplusplus)
extern "C" {
#endif

Expand All @@ -21,7 +35,6 @@ typedef enum _mb_comm_mode mb_mode_type_t;

#include "driver/uart.h"

__attribute__((__packed__))
struct _port_serial_opts {
mb_mode_type_t mode; /*!< Modbus communication mode */
uart_port_t port; /*!< Modbus communication port (UART) number */
Expand All @@ -32,7 +45,7 @@ struct _port_serial_opts {
uart_word_length_t data_bits; /*!< Modbus number of data bits */
uart_stop_bits_t stop_bits; /*!< Modbus number of stop bits */
uart_parity_t parity; /*!< Modbus UART parity settings */
};
} __attribute__((__packed__));

typedef struct _port_serial_opts mb_serial_opts_t;

Expand All @@ -44,16 +57,15 @@ typedef enum _addr_type_enum {
MB_IPV6 = 2 /*!< TCP IPV6 addressing */
} mb_addr_type_t;

__attribute__((__packed__))

struct _port_common_opts {
mb_mode_type_t mode; /*!< Modbus communication mode */
uint16_t port; /*!< Modbus communication port (UART) number */
uint8_t uid; /*!< Modbus slave address field (dummy for master) */
uint32_t response_tout_ms; /*!< Modbus slave response timeout */
uint64_t test_tout_us; /*!< Modbus test timeout (reserved) */
};
} __attribute__((__packed__));

__attribute__((__packed__))
struct _port_tcp_opts {
mb_mode_type_t mode; /*!< Modbus communication mode */
uint16_t port; /*!< Modbus communication port (UART) number */
Expand All @@ -65,7 +77,7 @@ struct _port_tcp_opts {
void *ip_netif_ptr; /*!< Modbus network interface */
char *dns_name; /*!< Modbus node DNS name */
bool start_disconnected; /*!< (Master only option) do not wait for connection to all nodes before polling */
};
} __attribute__((__packed__));

typedef struct _port_tcp_opts mb_tcp_opts_t;

Expand Down Expand Up @@ -100,7 +112,7 @@ typedef struct _uid_info {
uint16_t uid; /*!< node unit ID (UID) field for MBAP frame */
uint16_t port; /*!< node port number */
mb_comm_mode_t proto; /*!< protocol type */
_Atomic mb_sock_state_t state; /*!< node state */
_Atomic(int) state; /*!< node state */
void *inst; /*!< pointer to linked instance */
} mb_uid_info_t;

Expand Down
2 changes: 1 addition & 1 deletion modbus/mb_ports/common/mb_transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ typedef struct transaction_item {
int msg_id;
void *pnode;
transaction_tick_t tick;
_Atomic pending_state_t state;
_Atomic(int) state;
STAILQ_ENTRY(transaction_item) next;
} transaction_item_t;

Expand Down
4 changes: 2 additions & 2 deletions modbus/mb_ports/common/port_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ static const char *TAG = "mb_port.event";

struct mb_port_event_t
{
_Atomic mb_err_event_t curr_err_type;
_Atomic(int) curr_err_type;
SemaphoreHandle_t resource_hdl;
EventGroupHandle_t event_group_hdl;
QueueHandle_t event_hdl;
_Atomic uint64_t curr_trans_id;
_Atomic(uint64_t) curr_trans_id;
};

mb_err_enum_t mb_port_event_create(mb_port_base_t *inst)
Expand Down
2 changes: 1 addition & 1 deletion modbus/mb_ports/common/port_other.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "port_common.h"

/* ----------------------- Variables ----------------------------------------*/
static _Atomic uint32_t inst_counter = 0;
static _Atomic(uint32_t) inst_counter = 0;

/* ----------------------- Start implementation -----------------------------*/
int lock_obj(_lock_t *plock)
Expand Down
6 changes: 3 additions & 3 deletions modbus/mb_ports/common/port_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ struct mb_port_timer_t
//spinlock_t spin_lock;
esp_timer_handle_t timer_handle;
uint16_t t35_ticks;
_Atomic uint32_t response_time_ms;
_Atomic bool timer_state;
_Atomic uint16_t timer_mode;
_Atomic(uint32_t) response_time_ms;
_Atomic(bool) timer_state;
_Atomic(uint16_t) timer_mode;
};

/* ----------------------- Static variables ---------------------------------*/
Expand Down
2 changes: 1 addition & 1 deletion modbus/mb_ports/serial/port_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ typedef struct
uint64_t send_time_stamp;
uint64_t recv_time_stamp;
uint32_t flags;
bool enabled;
_Atomic(bool) enabled;
QueueHandle_t uart_queue; // A queue to handle UART event.
TaskHandle_t task_handle; // UART task to handle UART event.
SemaphoreHandle_t bus_sema_handle; // Rx blocking semaphore handle
Expand Down
6 changes: 6 additions & 0 deletions test_apps/cpp/modbus_serial_cpp_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mb_serial_cpp)
2 changes: 2 additions & 0 deletions test_apps/cpp/modbus_serial_cpp_test/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRCS "serial_test.cpp"
INCLUDE_DIRS ".")
6 changes: 6 additions & 0 deletions test_apps/cpp/modbus_serial_cpp_test/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies:
idf: ">=5.0"
espressif/esp-modbus:
version: "^2.0.0"
override_path: "../../../../"

130 changes: 130 additions & 0 deletions test_apps/cpp/modbus_serial_cpp_test/main/serial_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include "esp_log.h"

#include "sdkconfig.h"
#include "mbcontroller.h"

#define TEST_PORT_NUM (uart_port_t)1
#define TEST_SPEED 115200

#define TAG "CPP_TEST"
#define MB_SLAVE_SHORT_ADDRESS 1

enum {
MB_DEVICE_ADDR1 = 1
};

// Enumeration of all supported CIDs for device (used in parameter definition table)
enum {
CID_DEV_REG0 = 0
};

#define STR(fieldname) ((const char*)( fieldname ))
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }

static void *pmaster_handle = NULL;
static void *pslave_handle = NULL;

// Example Data (Object) Dictionary for Modbus parameters
const mb_parameter_descriptor_t dummy_dict[] = {
// CID, Name, Units, Modbus addr, register type, Modbus Reg Start Addr, Modbus Reg read length,
// Instance offset (NA), Instance type, Instance length (bytes), Options (NA), Permissions
{ CID_DEV_REG0, STR("MB_hold_reg-0"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
0, PARAM_TYPE_U16, PARAM_SIZE_U16, OPTS( 0,0,0 ), PAR_PERMS_READ_WRITE_TRIGGER },
};

// Calculate number of parameters in the table
const uint16_t num_device_parameters = (sizeof(dummy_dict)/sizeof(dummy_dict[0]));

// Modbus serial master initialization
static esp_err_t master_serial_init(void **pinst)
{
mb_communication_info_t comm;
comm.ser_opts.port = (uart_port_t)TEST_PORT_NUM;
comm.ser_opts.mode = (mb_comm_mode_t)MB_RTU;
comm.ser_opts.baudrate = TEST_SPEED;
comm.ser_opts.parity = MB_PARITY_NONE;
comm.ser_opts.uid = 0;
comm.ser_opts.response_tout_ms = 100;
comm.ser_opts.data_bits = UART_DATA_8_BITS;
comm.ser_opts.stop_bits = UART_STOP_BITS_1;
// Initialize Modbus controller
esp_err_t err = mbc_master_create_serial(&comm, pinst);
MB_RETURN_ON_FALSE((pinst != NULL), ESP_ERR_INVALID_STATE, TAG,
"mbc master initialization fail.");
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mbc master initialization fail, returns(0x%x).", (int)err);
err = mbc_master_set_descriptor(*pinst, &dummy_dict[0], num_device_parameters);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mbc master set descriptor fail, returns(0x%x).", (int)err);
err = mbc_master_start(*pinst);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mbc master start fail, returned (0x%x).", (int)err);
const mb_parameter_descriptor_t *pdescriptor = NULL;
err = mbc_master_get_cid_info(*pinst, CID_DEV_REG0, &pdescriptor);
MB_RETURN_ON_FALSE(((err != ESP_ERR_NOT_FOUND) && (pdescriptor != NULL)), ESP_ERR_INVALID_STATE, TAG,
"mbc master get descriptor fail, returned (0x%x).", (int)err);
uint16_t regs[] = {0x1111, 0x2222};
uint8_t type = 0;
err = mbc_master_get_parameter(*pinst, pdescriptor->cid, (uint8_t *)&regs[0], &type);
MB_RETURN_ON_FALSE((err != ESP_ERR_INVALID_STATE), ESP_ERR_INVALID_STATE, TAG,
"mbc master get parameter fail, returned (0x%x).", (int)err);
ESP_LOGI(TAG, "Modbus master stack initialized...");
return ESP_OK;
}

// Modbus serial slave initialization
static esp_err_t slave_serial_init(void **pinst)
{
mb_register_area_descriptor_t reg_area;
mb_communication_info_t comm;
comm.ser_opts.port = (uart_port_t)TEST_PORT_NUM;
comm.ser_opts.mode = (mb_comm_mode_t)MB_RTU;
comm.ser_opts.baudrate = TEST_SPEED;
comm.ser_opts.parity = MB_PARITY_NONE;
comm.ser_opts.uid = MB_SLAVE_SHORT_ADDRESS;
comm.ser_opts.response_tout_ms = 100;
comm.ser_opts.data_bits = UART_DATA_8_BITS;
comm.ser_opts.stop_bits = UART_STOP_BITS_1;
// Initialize Modbus controller
esp_err_t err = mbc_slave_create_serial(&comm, pinst);
MB_RETURN_ON_FALSE((pinst != NULL), ESP_ERR_INVALID_STATE, TAG,
"mbc slave initialization fail.");
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mbc slave initialization fail, returns(0x%x).", (int)err);
uint16_t holding_regs[] = {0x1111, 0x2222, 0x3333, 0x4444};
reg_area.type = MB_PARAM_HOLDING;
reg_area.start_offset = 0;
reg_area.address = (void*)&holding_regs[0];
reg_area.size = sizeof(holding_regs);
reg_area.access = MB_ACCESS_RW;
ESP_ERROR_CHECK(mbc_slave_set_descriptor(*pinst, reg_area));
err = mbc_slave_start(*pinst);
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mbc slave start fail, returned (0x%x).", (int)err);
ESP_LOGI(TAG, "Modbus slave stack initialized...");
return err;
}

// Intentionally verify that atomic values are layout compatible with original types
// Note: the `__is_layout_compatible() and ` is not supported in old versions
static_assert(
sizeof(std::atomic_int) == sizeof(int) &&
sizeof(std::atomic<int>) == sizeof(int) &&
sizeof(_Atomic(int)) == sizeof(int) &&
sizeof(_Atomic(uint32_t)) == sizeof(uint32_t) &&
sizeof(_Atomic(uint16_t)) == sizeof(uint16_t) &&
sizeof(_Atomic(uint64_t)) == sizeof(uint64_t)
);

extern "C" void app_main(void)
{
// Initialization of device peripheral and objects
ESP_LOGI(TAG, "Setup master cpp....");
ESP_ERROR_CHECK(master_serial_init(&pmaster_handle));
ESP_ERROR_CHECK(mbc_master_delete(pmaster_handle));
ESP_LOGI(TAG, "Master test passed successfully.");
ESP_LOGI(TAG, "Setup slave cpp....");
ESP_ERROR_CHECK(slave_serial_init(&pslave_handle));
ESP_ERROR_CHECK(mbc_slave_delete(pslave_handle));
ESP_LOGI(TAG, "Slave test passed successfully.");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
from pytest_embedded import Dut

@pytest.mark.esp32
@pytest.mark.generic
def test_cpp_mb_serial_master_slave(dut: Dut) -> None:
dut.expect('Setup master cpp....')
dut.expect('Modbus master stack initialized...', timeout=5)
dut.expect('Master test passed successfully.', timeout=5)
dut.expect('Setup slave cpp....')
dut.expect('Modbus slave stack initialized...', timeout=5)
dut.expect('Slave test passed successfully.', timeout=5)
dut.expect('Returned from app_main()')
2 changes: 1 addition & 1 deletion test_apps/test_common/mb_utest_lib/port_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ typedef struct _mb_adapter_port_entry
uint16_t recv_length;
uint64_t send_time_stamp;
uint64_t recv_time_stamp;
_Atomic uint64_t test_timeout_us;
_Atomic(uint64_t) test_timeout_us;
uint32_t flags;
mb_uid_info_t addr_info;
QueueHandle_t rx_queue;
Expand Down