mirror of
https://github.com/espressif/esp-modbus.git
synced 2025-06-25 01:01:33 +02:00
modbus add extended float/integer support for custom and third party devices
This commit is contained in:
@ -106,6 +106,9 @@ after_script:
|
||||
--manifest-file .build-test-rules.yml
|
||||
--parallel-count ${CI_NODE_TOTAL:-1}
|
||||
--parallel-index ${CI_NODE_INDEX:-1}
|
||||
# delete all other build artifacts, except esp32
|
||||
- echo "delete build folders:" $(find . -type d -regex '^\./.*build_esp32[a-z]+[0-9]+[_a-z]*' -print -exec rm -rf {} +)
|
||||
|
||||
variables:
|
||||
TEST_TARGETS: "esp32"
|
||||
|
||||
@ -121,11 +124,11 @@ build_idf_v5.0:
|
||||
variables:
|
||||
TEST_TARGETS: "esp32 esp32s2 esp32s3 esp32c2 esp32c3"
|
||||
|
||||
build_idf_v4.4:
|
||||
build_idf_v5.2:
|
||||
extends: .build_pytest_template
|
||||
image: espressif/idf:release-v4.4
|
||||
image: espressif/idf:release-v5.2
|
||||
variables:
|
||||
TEST_TARGETS: "esp32 esp32s2 esp32s3 esp32c3"
|
||||
TEST_TARGETS: "esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2"
|
||||
|
||||
.target_test_template:
|
||||
stage: target_test
|
||||
@ -162,7 +165,7 @@ build_idf_v4.4:
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${TEST_DIR}/${TEST_PORT}
|
||||
- echo "Start test for [esp-idf_${IDF_BRANCH}_${IDF_TARGET}_${TEST_PORT}]"
|
||||
- echo "Start target test for [esp-idf_${IDF_BRANCH}_${IDF_TARGET}_${TEST_PORT}]"
|
||||
- python -m pytest --junit-xml=${TEST_DIR}/${TEST_PORT}/results_${IDF_TARGET}_${IDF_BRANCH}.xml --target=${IDF_TARGET}
|
||||
- ls -lh > ${TEST_DIR}/test_dir.txt
|
||||
|
||||
@ -170,12 +173,12 @@ target_test:
|
||||
stage: target_test
|
||||
image: "$CI_DOCKER_REGISTRY/target-test-env-v5.2:2"
|
||||
extends: .test_template
|
||||
needs: [build_idf_master, build_idf_v4.4, build_idf_v5.0]
|
||||
needs: [build_idf_master, build_idf_v5.2, build_idf_v5.0]
|
||||
parallel:
|
||||
matrix:
|
||||
- IDF_BRANCH: ["master", "v4.4", "v5.0"]
|
||||
- IDF_BRANCH: ["master", "v5.2", "v5.0"]
|
||||
IDF_TARGET: ["esp32"]
|
||||
TEST_PORT: ["serial", "tcp"]
|
||||
TEST_PORT: ["serial", "tcp", "generic"]
|
||||
after_script: []
|
||||
|
||||
build_docs:
|
||||
|
@ -53,6 +53,10 @@ list(APPEND priv_include_dirs serial_slave/port serial_slave/modbus_controller
|
||||
tcp_slave/port tcp_slave/modbus_controller
|
||||
tcp_master/port tcp_master/modbus_controller)
|
||||
|
||||
if(CONFIG_FMB_EXT_TYPE_SUPPORT)
|
||||
list(APPEND srcs "common/mb_endianness_utils.c")
|
||||
endif()
|
||||
|
||||
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/freemodbus/" ${srcs})
|
||||
add_prefix(include_dirs "${CMAKE_CURRENT_LIST_DIR}/freemodbus/" ${include_dirs})
|
||||
add_prefix(priv_include_dirs "${CMAKE_CURRENT_LIST_DIR}/freemodbus/" ${priv_include_dirs})
|
||||
|
9
Kconfig
9
Kconfig
@ -221,4 +221,13 @@ menu "Modbus configuration"
|
||||
This option has dependency with the UART_ISR_IN_IRAM option which places UART interrupt
|
||||
handler into IRAM to prevent delays related to processing of UART events.
|
||||
|
||||
config FMB_EXT_TYPE_SUPPORT
|
||||
bool "Modbus uses extended types to support third party devices"
|
||||
default n
|
||||
help
|
||||
If this option is set the Modbus stack supports extended list of types
|
||||
in data dictionary and conversion API to work with the extended types
|
||||
otherwise the only legacy types are supported. The extended types include
|
||||
integer, float, double types with different endianness and size.
|
||||
|
||||
endmenu
|
||||
|
@ -13,17 +13,20 @@
|
||||
# http://doxygen.nl/manual/config.html
|
||||
|
||||
|
||||
PROJECT_NAME = "IDF Programming Guide"
|
||||
PROJECT_NAME = "ESP-MODBUS Programming Guide"
|
||||
|
||||
## The 'INPUT' statement below is used as input by script 'gen-df-input.py'
|
||||
## to automatically generate API reference list files heder_file.inc
|
||||
## These files are placed in '_inc' directory
|
||||
## and used to include in API reference documentation
|
||||
|
||||
##
|
||||
|
||||
INPUT = \
|
||||
$(PROJECT_PATH)/freemodbus/common/include/esp_modbus_common.h \
|
||||
$(PROJECT_PATH)/freemodbus/common/include/esp_modbus_slave.h \
|
||||
$(PROJECT_PATH)/freemodbus/common/include/esp_modbus_master.h \
|
||||
$(PROJECT_PATH)/freemodbus/common/include/mb_endianness_utils.h
|
||||
|
||||
## Get warnings for functions that have no documentation for their parameters or return value
|
||||
##
|
||||
|
37
docs/_static/diag_frame.diag
vendored
Normal file
37
docs/_static/diag_frame.diag
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
# Modbus float_abcd frame structure diagram
|
||||
|
||||
blockdiag mb_float_frame {
|
||||
# global properties
|
||||
span_width = 2;
|
||||
span_height = 5;
|
||||
node_height = 25;
|
||||
default_fontsize = 16;
|
||||
default_group_color = lightgrey;
|
||||
class spacer [shape=none, width=10];
|
||||
# tuning node properties and connections
|
||||
0,1,2 [class=spacer];
|
||||
0; note
|
||||
1; header
|
||||
2; response -- uid -- cmd -- len -- fl_abcd -- crc
|
||||
group float_abcd_packet {
|
||||
label = "PDU";
|
||||
color = gray;
|
||||
shape = line;
|
||||
style = dashed;
|
||||
group{uid,resp_uid};group{cmd,resp_cmd};group{len,resp_len};group{crc,resp_crc};
|
||||
group float_abcd{
|
||||
color = blue;
|
||||
shape = line;
|
||||
style = dashed;
|
||||
fl_abcd;dt_abcd;
|
||||
}
|
||||
}
|
||||
note[label="1: Unit Identificator, 2: Function code, 3: Data length, 4: Float data array, 5: Checksum",colwidth=6,color=lightyellow,shape=roundedbox]
|
||||
header[label="FLOAT_ABCD = 0x4640e400 = 12345.0",colwidth=6,color=lightgreen]
|
||||
response[label="RX:",color=yellow];
|
||||
uid[label="UID",numbered=1];cmd[label="FC",numbered=2];
|
||||
len[label="LENGTH",numbered=3];crc[label="CRC",numbered=5];
|
||||
resp_uid[label="0x01"];resp_cmd[label="0x03"];resp_len[label="0x08"];resp_crc[label="0x9065"];
|
||||
fl_abcd[label="FLOAT_ABCD",color=lightgreen,numbered=4];
|
||||
dt_abcd[label="0xE4004640",shape=note];
|
||||
}
|
61
docs/_static/modbus_frame_examples.diag
vendored
Normal file
61
docs/_static/modbus_frame_examples.diag
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
# Modbus frame packaging examples
|
||||
|
||||
blockdiag mb_master_frames {
|
||||
# global properties
|
||||
span_width = 5;
|
||||
span_height = 5;
|
||||
node_height = 25;
|
||||
default_group_color = lightgrey;
|
||||
default_fontsize = 15;
|
||||
# tuning node properties and connections
|
||||
group 16bit_packets {
|
||||
label = "16bit frame";
|
||||
color = red;
|
||||
shape = line;
|
||||
style = dashed;
|
||||
16bit_notes;
|
||||
}
|
||||
group 32bit_packets {
|
||||
label = "32bit frame";
|
||||
color = green;
|
||||
shape = line;
|
||||
style = dashed;
|
||||
group{32bit_notes};
|
||||
}
|
||||
group 64bit_packets {
|
||||
label = "64bit frame";
|
||||
color = blue;
|
||||
shape = line;
|
||||
style = dashed;
|
||||
64bit_notes;
|
||||
}
|
||||
16bit_notes[label="UINT16, INT16 VALUE = 0x3039 = (uint16_t)12345", width=600, color=orange, shape = roundedbox];
|
||||
req_u16_hd1[label= "TX:| UID | FC | REG_START | REG_LEN | CRC |", color=lightyellow, width=380, colwidth=2, shape = roundedbox ,group=16bit_packets];
|
||||
req_u16_frm1[label="TX:| 01 | 03 | 00 04 | 00 02 | 85 CA |", color=lightgrey, width=380, colwidth=2,group=16bit_packets];
|
||||
rsp_u16_hd1[label= "RX:| UID | FC | LEN | UINT16_AB1 | UINT16_AB2 | CRC |", color=lightyellow, width=380, colwidth=2, shape = roundedbox ,group=16bit_packets];
|
||||
rsp_u16_frm1[label="RX:| 01 | 03 | 04 | 30 39 | 30 39 | F1 2C |", color=lightgrey, width=380, colwidth=2,group=16bit_packets];
|
||||
rsp_u16_hd2[label= "RX:| UID | FC | LEN | UINT16_BA1 | UINT16_BA2 | CRC |\n ", color=lightyellow, width=380, colwidth=2, shape = roundedbox, group=16bit_packets];
|
||||
rsp_u16_frm2[label="RX:| 01 | 03 | 04 | 39 30 | 39 30 | E4 E4 |\n", color=lightgrey, width=380, colwidth=2,group=16bit_packets];
|
||||
32bit_notes[label="(UINT32, INT32) FLOAT32 VALUE = 0x4640e400 = 12345.0", width=600, color=lightgreen, shape = roundedbox];
|
||||
req_fl_hd1[label= "TX:| UID | FC | REG_START | REG_LEN | CRC |", color=lightyellow, width=380, colwidth=2, shape = roundedbox ,group=32bit_packets];
|
||||
req_fl_frm1[label="TX:| 01 | 03 | 00 XX | 00 04 | C5 CB |", color=lightgrey, width=380, colwidth=2,group=32bit_packets];
|
||||
rsp_fl_hd1[label= "RX:| UID | FC | LEN | FLOAT_ABCD1 | FLOAT_ABCD2 | CRC |", color=lightyellow, width=380, colwidth=2, shape = roundedbox ,group=32bit_packets];
|
||||
rsp_fl_frm1[label="RX:| 01 | 03 | 08 | E4 00 46 40 | E4 00 46 40 | 90 65 |", color=lightgrey, width=380, colwidth=2,group=32bit_packets];
|
||||
rsp_fl_hd2[label= "RX:| UID | FC | LEN | FLOAT_CDAB1 | FLOAT_CDAB2 | CRC |\n ", color=lightyellow, width=380, colwidth=2, shape = roundedbox, group=32bit_packets];
|
||||
rsp_fl_frm2[label="RX:| 01 | 03 | 08 | 46 40 E4 00 | 46 40 E4 00 | 18 71 |\n", color=lightgrey, width=380, colwidth=2,group=32bit_packets];
|
||||
rsp_fl_hd3[label= "RX:| UID | FC | LEN | FLOAT_BADC1 | FLOAT_BADC2 | CRC |\n ", color=lightyellow, width=380, colwidth=2, shape = roundedbox, group=32bit_packets];
|
||||
rsp_fl_frm3[label="RX:| 01 | 03 | 08 | 00 E4 40 46 | 00 E4 40 46 | 46 D3 |\n", color=lightgrey, width=380, colwidth=2,group=32bit_packets];
|
||||
rsp_fl_hd4[label= "RX:| UID | FC | LEN | FLOAT_DCAB1 | FLOAT_DCAB2 | CRC |\n ", color=lightyellow, width=380, colwidth=2, shape = roundedbox, group=32bit_packets];
|
||||
rsp_fl_frm4[label="RX:| 01 | 03 | 08 | 40 46 00 E4 | 40 46 00 E4 | 32 6B |\n", color=lightgrey, width=380, colwidth=2,group=32bit_packets];
|
||||
64bit_notes[label="(UINT64, INT64) FLOAT64 VALUE = 0x40c81c8000000000 = 12345.0", width=600, color=lightblue, shape = roundedbox];
|
||||
req_dbl_hd1[label= "TX:| UID | FC | REG_START | REG_LEN | CRC |", color=lightyellow, width=380, colwidth=2, shape = roundedbox ,group=64bit_packets];
|
||||
req_dbl_frm1[label="TX:| 01 | 03 | 00 28 | 00 08 | C4 04 |", color=lightgrey, width=380, colwidth=2,group=64bit_packets];
|
||||
rsp_dbl_hd1[label= "RX:| UID | FC | LEN | DOUBLE_ABCDEFGH1 | DOUBLE_ABCDEFGH2 | CRC |", color=lightyellow, width=380, colwidth=2, shape = roundedbox ,group=64bit_packets];
|
||||
rsp_dbl_frm1[label="RX:| 01 | 03 | 10 | 00 00 00 00 1C 80 40 C8 | 00 00 00 00 1C 80 40 C8 | 9F 4B |", color=lightgrey, width=380, colwidth=2,group=64bit_packets];
|
||||
rsp_dbl_hd2[label= "RX:| UID | FC | LEN | DOUBLE_HGFEDCBA1 | DOUBLE_HGFEDCBA2 | CRC |\n ", color=lightyellow, width=380, colwidth=2, shape = roundedbox, group=64bit_packets];
|
||||
rsp_dbl_frm2[label="RX:| 01 | 03 | 10 | C8 40 80 1C 00 00 00 00 | C8 40 80 1C 00 00 00 00 | DF D3 |\n", color=lightgrey, width=380, colwidth=2,group=64bit_packets];
|
||||
rsp_dbl_hd3[label= "RX:| UID | FC | LEN | DOUBLE_GHEFCDAB1 | DOUBLE_GHEFCDAB2 | CRC |\n ", color=lightyellow, width=380, colwidth=2, shape = roundedbox, group=64bit_packets];
|
||||
rsp_dbl_frm3[label="RX:| 01 | 03 | 10 | 40 C8 1C 80 00 00 00 00 | 40 C8 1C 80 00 00 00 00 | B1 9C |\n", color=lightgrey, width=380, colwidth=2,group=64bit_packets];
|
||||
rsp_dbl_hd4[label= "RX:| UID | FC | LEN | DOUBLE_BADCFEHG1 | DOUBLE_BADCFEHG2 | CRC |\n ", color=lightyellow, width=380, colwidth=2, shape = roundedbox, group=64bit_packets];
|
||||
rsp_dbl_frm4[label="RX:| 01 | 03 | 10 | 00 00 00 00 80 1C C8 40 | 00 00 00 00 80 1C C8 40 | 86 94 |\n", color=lightgrey, width=380, colwidth=2,group=64bit_packets];
|
||||
}
|
@ -70,4 +70,9 @@ API Reference
|
||||
.. include-build-file:: inc/esp_modbus_master.inc
|
||||
.. include-build-file:: inc/esp_modbus_slave.inc
|
||||
|
||||
.. _modbus_api_endianness_conversion:
|
||||
|
||||
Modbus Endianness Conversion API Reference
|
||||
------------------------------------------
|
||||
|
||||
.. include-build-file:: inc/mb_endianness_utils.inc
|
@ -11,4 +11,4 @@ The Modbus is a data communications protocol originally published by Modicon (no
|
||||
Modbus Port Initialization <port_initialization>
|
||||
Modbus Master API <master_api_overview>
|
||||
Modbus Slave API <slave_api_overview>
|
||||
Applications and References <applications_and_references>
|
||||
Applications and References <applications_and_references>
|
||||
|
@ -16,10 +16,7 @@ The following overview describes how to setup Modbus master communication. The o
|
||||
Configuring Master Data Access
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The architectural approach of ESP_Modbus includes one level above standard Modbus IO driver.
|
||||
The additional layer is called Modbus controller and its goal is to add an abstraction such as CID - characteristic identifier.
|
||||
The CID is linked to a corresponding Modbus registers through the table called Data Dictionary and represents device physical parameter (such as temperature, humidity, etc.) in specific Modbus slave device.
|
||||
This approach allows the upper layer (e.g., MESH or MQTT) to be isolated from Modbus specifics thus simplify Modbus integration with other protocols/networks.
|
||||
The architectural approach of ESP_Modbus includes one level above standard Modbus IO driver. The additional layer is called Modbus controller and its goal is to add an abstraction such as CID - characteristic identifier. The CID is linked to a corresponding Modbus registers through the table called Data Dictionary and represents device physical parameter (such as temperature, humidity, etc.) in specific Modbus slave device. This approach allows the upper layer (e.g., MESH or MQTT) to be isolated from Modbus specifics thus simplify Modbus integration with other protocols/networks.
|
||||
|
||||
The Data Dictionary is the list in the Modbus master which shall be defined by user to link each CID to its corresponding Modbus registers representation using Register Mapping table of the Modbus slave being used.
|
||||
Each element in this data dictionary is of type :cpp:type:`mb_parameter_descriptor_t` and represents the description of one physical characteristic:
|
||||
@ -52,20 +49,17 @@ Each element in this data dictionary is of type :cpp:type:`mb_parameter_descript
|
||||
- Relative register address of the characteristic in the register area.
|
||||
* - ``mb_size``
|
||||
- Modbus Register Size
|
||||
- Length of characteristic in registers.
|
||||
- Length of characteristic in registers (two bytes).
|
||||
* - ``param_offset``
|
||||
- Instance Offset
|
||||
- Offset to instance of the characteristic in bytes. It is used to calculate the absolute address to the characteristic in the storage structure.
|
||||
It is optional field and can be set to zero if the parameter is not used in the application.
|
||||
* - ``param_type``
|
||||
- Data Type
|
||||
- Specifies type of the characteristic.
|
||||
:cpp:enumerator:`PARAM_TYPE_U8`, :cpp:enumerator:`PARAM_TYPE_U16`, :cpp:enumerator:`PARAM_TYPE_U32` - Unsigned integer 8/16/32 bit type;
|
||||
:cpp:enumerator:`PARAM_TYPE_FLOAT` - IEEE754 floating point format;
|
||||
:cpp:enumerator:`PARAM_TYPE_ASCII` - ASCII string or binary data;
|
||||
- Data Type
|
||||
- Specifies type of the characteristic. Possible types are described in the section :ref:`modbus_mapping_complex_data_types`.
|
||||
* - ``param_size``
|
||||
- Data Size
|
||||
- The storage size of the characteristic (bytes).
|
||||
- The storage size of the characteristic (in bytes) describes the size of data to keep into data instance during mapping. For the :ref:`modbus_mapping_complex_data_types` this allows to define the data container of the corresponded type.
|
||||
* - ``param_opts``
|
||||
- Parameter Options
|
||||
- Limits, options of characteristic used during processing of alarm in user application (optional)
|
||||
@ -76,6 +70,13 @@ Each element in this data dictionary is of type :cpp:type:`mb_parameter_descript
|
||||
|
||||
.. note:: The ``cid`` and ``param_key`` have to be unique. Please use the prefix to the parameter key if you have several similar parameters in your register map table.
|
||||
|
||||
Examples Of Mapping
|
||||
@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
Please refer to section :ref:`modbus_mapping_complex_data_types` for more information about used data types.
|
||||
|
||||
Example 1: Configure access to legacy parameter types is described below.
|
||||
|
||||
.. list-table:: Table 2 Example Register mapping table of Modbus slave
|
||||
:widths: 5 5 2 10 5 5 68
|
||||
:header-rows: 1
|
||||
@ -115,6 +116,7 @@ Each element in this data dictionary is of type :cpp:type:`mb_parameter_descript
|
||||
- ASCII or binary array
|
||||
- Not defined
|
||||
- Device name (16 bytes) ASCII string. The type of `PARAM_TYPE_ASCII` allows to read/write complex parameter (string or binary data) that corresponds to one CID.
|
||||
|
||||
.. code:: c
|
||||
|
||||
// Enumeration of modbus slave addresses accessed by master device
|
||||
@ -160,10 +162,139 @@ Each element in this data dictionary is of type :cpp:type:`mb_parameter_descript
|
||||
// Calculate number of parameters in the table
|
||||
uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
|
||||
|
||||
Example 2: Configure access using extended parameter types for third-party devices.
|
||||
|
||||
.. list-table:: Table 3 Example Register mapping table of Modbus slave
|
||||
:widths: 2 4 2 10 3 68
|
||||
:header-rows: 1
|
||||
|
||||
* - CID
|
||||
- Register
|
||||
- Length
|
||||
- Range
|
||||
- Units
|
||||
- Description
|
||||
* - 0
|
||||
- 40000
|
||||
- 4
|
||||
- 0 ... 255
|
||||
- No units
|
||||
- :cpp:enumerator:`PARAM_TYPE_U8_A` - unsigned integer 8-bit
|
||||
* - 1
|
||||
- 40002
|
||||
- 4
|
||||
- 0 ... 65535
|
||||
- No Units
|
||||
- :cpp:enumerator:`PARAM_TYPE_U16_AB` uinsigned integer 16-bit
|
||||
* - 3
|
||||
- 40004
|
||||
- 8
|
||||
- 0 ... Unsigned integer 32-bit range
|
||||
- No units
|
||||
- :cpp:enumerator:`PARAM_TYPE_U32_ABCD` - unsigned integer 32-bit in ABCD format
|
||||
* - 4
|
||||
- 40008
|
||||
- 8
|
||||
- 0 ... Unsigned integer 32-bit range
|
||||
- No units
|
||||
- :cpp:enumerator:`PARAM_TYPE_FLOAT_CDAB` - FLOAT 32-bit value in CDAB format
|
||||
* - 5
|
||||
- 400012
|
||||
- 16
|
||||
- 0 ... Unsigned integer 64-bit range
|
||||
- No units
|
||||
- :cpp:enumerator:`PARAM_TYPE_U64_ABCDEFGH` - Unsigned integer 64-bit value in ABCDEFGH format
|
||||
* - 6
|
||||
- 400020
|
||||
- 16
|
||||
- 0 ... Unsigned integer 64-bit range
|
||||
- No units
|
||||
- :cpp:enumerator:`PARAM_TYPE_DOUBLE_HGFEDCBA` - Double precision 64-bit value in HGFEDCBA format
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include "limits.h"
|
||||
#include "mbcontroller.h"
|
||||
|
||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
||||
#define HOLD_REG_START(field) (HOLD_OFFSET(field) >> 1)
|
||||
#define HOLD_REG_SIZE(field) (sizeof(((holding_reg_params_t *)0)->field) >> 1)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
// Example structure that contains parameter arrays of different types
|
||||
// with different options of endianness.
|
||||
typedef struct
|
||||
{
|
||||
uint16_t holding_u8_a[2];
|
||||
uint16_t holding_u16_ab[2];
|
||||
uint32_t holding_uint32_abcd[2];
|
||||
float holding_float_cdab[2];
|
||||
double holding_uint64_abcdefgh[2];
|
||||
double holding_double_hgfedcba[2];
|
||||
} holding_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
// Enumeration of modbus slave addresses accessed by master device
|
||||
enum {
|
||||
MB_DEVICE_ADDR1 = 1, // Short address of Modbus slave device
|
||||
MB_SLAVE_COUNT
|
||||
};
|
||||
|
||||
// Enumeration of all supported CIDs for device (used in parameter definition table)
|
||||
enum {
|
||||
CID_HOLD_U8_A = 0,
|
||||
CID_HOLD_U16_AB,
|
||||
CID_HOLD_UINT32_ABCD,
|
||||
CID_HOLD_FLOAT_CDAB,
|
||||
CID_HOLD_UINT64_ABCDEFGH,
|
||||
CID_HOLD_DOUBLE_HGFEDCBA,
|
||||
CID_COUNT
|
||||
};
|
||||
|
||||
// Example Data Dictionary for to address parameters from slaves with different options of endianness
|
||||
mb_parameter_descriptor_t device_parameters[] = {
|
||||
// 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_HOLD_U8_A, STR("U8_A"), STR("--"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
HOLD_REG_START(holding_u8_a), HOLD_REG_SIZE(holding_u8_a),
|
||||
HOLD_OFFSET(holding_u8_a), PARAM_TYPE_U8_A, (HOLD_REG_SIZE(holding_u8_a) << 1),
|
||||
OPTS( 0, UCHAR_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_U16_AB, STR("U16_AB"), STR("--"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
HOLD_REG_START(holding_u16_ab), HOLD_REG_SIZE(holding_u16_ab),
|
||||
HOLD_OFFSET(holding_u16_ab), PARAM_TYPE_U16_AB, (HOLD_REG_SIZE(holding_u16_ab) << 1),
|
||||
OPTS( 0, USHRT_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_ABCD, STR("UINT32_ABCD"), STR("--"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
HOLD_REG_START(holding_uint32_abcd), HOLD_REG_SIZE(holding_uint32_abcd),
|
||||
HOLD_OFFSET(holding_uint32_abcd), PARAM_TYPE_U32_ABCD, (HOLD_REG_SIZE(holding_uint32_abcd) << 1),
|
||||
OPTS( 0, ULONG_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_CDAB, STR("FLOAT_CDAB"), STR("--"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
HOLD_REG_START(holding_float_cdab), HOLD_REG_SIZE(holding_float_cdab),
|
||||
HOLD_OFFSET(holding_float_cdab), PARAM_TYPE_FLOAT_CDAB, (HOLD_REG_SIZE(holding_float_cdab) << 1),
|
||||
OPTS( 0, ULONG_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT64_ABCDEFGH, STR("UINT64_ABCDEFGH"), STR("--"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
HOLD_REG_START(holding_uint64_abcdefgh), HOLD_REG_SIZE(holding_uint64_abcdefgh),
|
||||
HOLD_OFFSET(holding_uint64_abcdefgh), PARAM_TYPE_UINT64_ABCDEFGH, (HOLD_REG_SIZE(holding_uint64_abcdefgh) << 1),
|
||||
OPTS( 0, ULLONG_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_HGFEDCBA, STR("DOUBLE_HGFEDCBA"), STR("--"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
HOLD_REG_START(holding_double_hgfedcba), HOLD_REG_SIZE(holding_double_hgfedcba),
|
||||
HOLD_OFFSET(holding_double_hgfedcba), PARAM_TYPE_DOUBLE_HGFEDCBA, (HOLD_REG_SIZE(holding_double_hgfedcba) << 1),
|
||||
OPTS( 0, ULLONG_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER }
|
||||
};
|
||||
uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
|
||||
|
||||
The example above describes the definition of just several extended types. The types described in the :ref:`modbus_mapping_complex_data_types` allow to address the most useful value formats from devices of known third-party vendors.
|
||||
Once the type of characteristic is defined in data dictionary the stack is responsible for conversion of values to/from the corresponding type option into the format recognizable by compiler.
|
||||
|
||||
.. note:: Please refer to your vendor device manual and its mapping table to select the types suitable for your device.
|
||||
|
||||
The Modbus stack contains also the :ref:`modbus_api_endianness_conversion` - endianness conversion API functions that allow to convert values from/to each extended type into compiler representation.
|
||||
|
||||
During initialization of the Modbus stack, a pointer to the Data Dictionary (called descriptor) must be provided as the parameter of the function below.
|
||||
|
||||
:cpp:func:`mbc_master_set_descriptor`: Initialization of master descriptor.
|
||||
|
||||
Initialization of master descriptor. The descriptor represents an array of type :cpp:type:`mb_parameter_descriptor_t` and describes all the characteristics accessed by master.
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(mbc_master_set_descriptor(&device_parameters[0], num_device_parameters));
|
||||
@ -226,7 +357,6 @@ Refer to :ref:`example TCP master <example_mb_tcp_master>` for more information.
|
||||
|
||||
.. note:: RS485 communication requires call to UART specific APIs to setup communication mode and pins. Refer to the `UART communication section <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/uart.html#uart-api-running-uart-communication>`__ in documentation.
|
||||
|
||||
|
||||
.. _modbus_api_master_start_communication:
|
||||
|
||||
Master Communication
|
||||
@ -265,7 +395,7 @@ Example:
|
||||
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) {
|
||||
err = mbc_master_get_parameter(param_descriptor->cid, (char*)param_descriptor->param_key, (uint8_t*)temp_data, &type);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx32 ") read successful.",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
@ -281,7 +411,6 @@ Example:
|
||||
ESP_LOGE(TAG, "Could not get information for characteristic %d.", cid);
|
||||
}
|
||||
|
||||
|
||||
:cpp:func:`mbc_master_set_parameter`
|
||||
|
||||
The function writes characteristic's value defined as a name and cid parameter in corresponded slave device. The additional data for parameter request is taken from master parameter description table.
|
||||
@ -298,7 +427,6 @@ The function writes characteristic's value defined as a name and cid parameter i
|
||||
ESP_LOGE(TAG, "Set data fail, err = 0x%x (%s).", (int)err, (char*)esp_err_to_name(err));
|
||||
}
|
||||
|
||||
|
||||
.. _modbus_api_master_destroy:
|
||||
|
||||
Modbus Master Teardown
|
||||
|
@ -39,9 +39,212 @@ The Modbus protocol allows devices to map data to four types of registers (Holdi
|
||||
|
||||
Modbus data mapping
|
||||
|
||||
.. _modbus_mapping_complex_data_types:
|
||||
|
||||
Mapping Of Complex Data Types
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
As per section 4.2 of Modbus specification, "MODBUS uses a ``big-Endian`` representation for addresses and data items. This means that when a numerical quantity larger than a single byte is transmitted, the most significant byte is sent first". The biggest official structure defined by the Modbus specification is a 16-bit word register, which is 2 bytes. However, vendors sometimes group two or even four 16-bit registers together to be interpretted as 32-bit or 64-bit values, respectively. It is also possible when the Modbus vendors group many registers together for serial numbers, text strings, time/date, etc. Regardless of how the vendor intends the data to be interpreted, the Modbus protocol itself simply transfers 16-bit word registers. These values grouped from registers may use either little-endian or big-endian register order.
|
||||
|
||||
.. note:: Each individual 16-bit register, is encoded in big-endian order (assuming the Modbus device abides by the Modbus specification). However, the 32-bit and 64-bit types naming conventions like ABCD or ABCDEFGH, does not take into account the network format byte order of frame. For example: the ABCD prefix for 32-bit values means the common Modbus mapping format and corresponds to the CDAB on network format (order in the frame).
|
||||
|
||||
Common Data Types Supported By Modbus Vendors
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
.. list-table:: Table 1 basic types used by Modbus vendors
|
||||
:widths: 8 3 20
|
||||
:header-rows: 1
|
||||
|
||||
* - Type
|
||||
- Range
|
||||
- Format description
|
||||
* - U8, I8 - Unsigned/Signed 8-bit type
|
||||
- (0 .. 255)/(-128 .. 127)
|
||||
- Common unsigned 8-bit type that is stored usually in one Modbus register. The value can be stored in HI or LO byte of the register or packed with the next byte into one 16 - bit register.
|
||||
* - U16 - Unsigned integer 16-bit type
|
||||
- 0 - 65535
|
||||
- Stored in one 16-bit register. The values can be stored with AB or BA endianness.
|
||||
* - I16 - Signed integer 16-bit type
|
||||
- -32768 to 32767 is allowed.
|
||||
- Stored in one 16-bit register. The values can be stored with AB or BA forendiannessmat.
|
||||
* - I32 - Signed long integer 32-bit type
|
||||
- -2147483648 to 2147483647 is allowed.
|
||||
- Stored in two consecutive 16-bit register. The values can be stored with ABCD - DCBA endianness (see below).
|
||||
* - U32 - Unsigned long integer 32-bit type
|
||||
- 0 to 4294967295 is allowed.
|
||||
- Stored in two consecutive 16-bit register. The values can be stored with ABCD - DCBA endianness.
|
||||
* - U64 Unsigned Long long integers (Unsigned integer 64)
|
||||
- 0 to 18446744073709551615 is allowed.
|
||||
- Stored in four consecutive 16-bit register. The values can be stored with ABCDEFGH - BADCFEHG endianness.
|
||||
* - I64 Signed Long long integers (Signed integer 64)
|
||||
- -9223372036854775808 to 9223372036854775807 is allowed.
|
||||
- Stored in four consecutive 16-bit register. The values can be stored with ABCDEFGH - BADCFEHG endianness.
|
||||
* - Floating point single precision 32-bit
|
||||
- 1.17549435E-38 to 3.40282347E+38 is allowed.
|
||||
- Stored in two consecutive 16-bit register per IEEE754. The values can be stored with ABCD - DCBA endianness.
|
||||
* - Floating point double precision 64-bit
|
||||
- +/-5.0E-324 to +/-1.7E+308 is allowed.
|
||||
- Stored in four consecutive 16-bit register per IEEE754. The values can be stored with ABCDEFGH - BADCFEHG endianness.
|
||||
|
||||
As showed in the table above the float and double types do not fit to the 16-bit register and reguire several consecutive registers be used to store the value. However, different manufacturers store the consecutive bytes in different order (not standardized). For example: The DCBA prefix means inversed Modbus format (BADC order on network format).
|
||||
|
||||
.. list-table:: Table 2 Modbus byte order for extended types
|
||||
:widths: 3 28
|
||||
:header-rows: 1
|
||||
|
||||
* - Postfix
|
||||
- Format description
|
||||
* - ABCD
|
||||
- Big endian, high order byte first
|
||||
* - CDAB
|
||||
- Big endian, reversed register order (Little endian with byte swap)
|
||||
* - BADC
|
||||
- Little endian, reversed register order (Big endian with byte swap)
|
||||
* - DCBA
|
||||
- Little endian (Low order byte first)
|
||||
|
||||
The extended data types are used to define all possible combinations of groupped values are represented below and correspond to ``param_type`` field of the data dictionary as described in the table below:
|
||||
|
||||
.. list-table:: Table 3 Modbus extended data types of characteristics
|
||||
:widths: 6 28 10
|
||||
:header-rows: 1
|
||||
|
||||
* - Type
|
||||
- Format type description (common format)
|
||||
- Format type (network format)
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U8`
|
||||
- compatibility type corresponds to :cpp:enumerator:`PARAM_TYPE_U8_A`
|
||||
- Unsigned integer 8 bit type
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U16`
|
||||
- Unsigned integer 16 bit type, corresponds to :cpp:enumerator:`PARAM_TYPE_U16_AB`
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U32`
|
||||
- Default unsigned integer 32 bit type, corresponds to :cpp:enumerator:`PARAM_TYPE_U32_ABCD`
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_FLOAT`
|
||||
- Default unsigned integer 32 bit type, corresponds to :cpp:enumerator:`PARAM_TYPE_FLOAT_ABCD`
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_ASCII`
|
||||
- Default ASCII string format
|
||||
- Packed ASCII string data
|
||||
* - :cpp:enumerator:`PARAM_TYPE_BIN`
|
||||
- Binary data type
|
||||
- Default type for binary packed data
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I8_A`
|
||||
- I8 signed integer in low byte of register, high byte is zero
|
||||
- I8 signed integer LO
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I8_B`
|
||||
- I8 signed integer in high byte of register, low byte is zero
|
||||
- I8 signed integer HI
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U8_A`
|
||||
- U8 unsigned integer written to low byte of register, high byte is zero
|
||||
- U8 unsigned integer LO
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U8_B`
|
||||
- U8 unsigned integer written to hi byte of register, low byte is zero
|
||||
- U8 unsigned integer HI
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I16_AB`
|
||||
- I16 signed integer, big endian
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I16_BA`
|
||||
- I16 signed integer, little endian
|
||||
- Little endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U16_AB`
|
||||
- U16 unsigned integer, big endian
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U16_BA`
|
||||
- U16 unsigned integer, little endian
|
||||
- Little endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I32_ABCD`
|
||||
- I32 ABCD signed integer, big endian
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I32_CDAB`
|
||||
- I32 CDAB signed integer, big endian, reversed register order
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I32_BADC`
|
||||
- I32 BADC signed integer, little endian, reversed register order
|
||||
- Little endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I32_DCBA`
|
||||
- I32 DCBA signed integer, little endian
|
||||
- Big endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U32_ABCD`
|
||||
- U32 ABCD unsigned integer, big endian
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U32_CDAB`
|
||||
- U32 CDAB unsigned integer, big endian, reversed register order
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U32_BADC`
|
||||
- U32 BADC unsigned integer, little endian, reversed register order
|
||||
- Little endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U32_DCBA`
|
||||
- U32 DCBA unsigned integer, little endian
|
||||
- Big endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_FLOAT_ABCD`
|
||||
- Float ABCD floating point, big endian
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_FLOAT_CDAB`
|
||||
- Float CDAB floating point, big endian, reversed register order
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_FLOAT_BADC`
|
||||
- Float BADC floating point, little endian, reversed register order
|
||||
- Little endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_FLOAT_DCBA`
|
||||
- Float DCBA floating point, little endian
|
||||
- Big endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I64_ABCDEFGH`
|
||||
- I64, ABCDEFGH signed integer, big endian
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I64_HGFEDCBA`
|
||||
- I64, HGFEDCBA signed integer, little endian
|
||||
- Big endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I64_GHEFCDAB`
|
||||
- I64, GHEFCDAB signed integer, big endian, reversed register order
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_I64_BADCFEHG`
|
||||
- I64, BADCFEHG signed integer, little endian, reversed register order
|
||||
- Little endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U64_ABCDEFGH`
|
||||
- U64, ABCDEFGH unsigned integer, big endian
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U64_HGFEDCBA`
|
||||
- U64, HGFEDCBA unsigned integer, little endian
|
||||
- Big endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U64_GHEFCDAB`
|
||||
- U64, GHEFCDAB unsigned integer, big endian, reversed register order
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_U64_BADCFEHG`
|
||||
- U64, BADCFEHG unsigned integer, little endian, reversed register order
|
||||
- Little endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_DOUBLE_ABCDEFGH`
|
||||
- Double ABCDEFGH floating point, big endian
|
||||
- Little endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_DOUBLE_HGFEDCBA`
|
||||
- Double HGFEDCBA floating point, little endian
|
||||
- Big endian byte swap
|
||||
* - :cpp:enumerator:`PARAM_TYPE_DOUBLE_GHEFCDAB`
|
||||
- Double GHEFCDAB floating point, big endian, reversed register order
|
||||
- Big endian
|
||||
* - :cpp:enumerator:`PARAM_TYPE_DOUBLE_BADCFEHG`
|
||||
- Double BADCFEHG floating point, little endian, reversed register order
|
||||
- Little endian
|
||||
|
||||
.. note:: The support for the extended data types should be enabled using the option ``CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND`` in kconfig menu.
|
||||
|
||||
The below diagrams show how the extended data types appear on network layer.
|
||||
|
||||
.. blockdiag:: /../_static/diag_frame.diag
|
||||
:scale: 80%
|
||||
:caption: Modbus master response with ABCD frame
|
||||
:align: center
|
||||
|
||||
.. blockdiag:: /../_static/modbus_frame_examples.diag
|
||||
:scale: 80%
|
||||
:caption: Modbus frame packaging examples (16-bit, 32-bit, 64-bit data)
|
||||
:align: center
|
||||
|
||||
The approach showed above can be used to pack the data into MBAP frames used by Modbus TCP as well as for other types with similar size.
|
||||
|
||||
The following sections give an overview of how to use the ESP_Modbus component found under `components/freemodbus`. The sections cover initialization of a Modbus port, and the setup a master or slave device accordingly:
|
||||
|
||||
- :ref:`modbus_api_port_initialization`
|
||||
- :ref:`modbus_api_slave_overview`
|
||||
- :ref:`modbus_api_master_overview`
|
||||
|
||||
|
@ -32,4 +32,4 @@ This example code to initialize slave port:
|
||||
if (slave_handler == NULL || err != ESP_OK) {
|
||||
// Error handling is performed here
|
||||
ESP_LOGE(TAG, "mb controller initialization fail.");
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,31 @@ Direct access to register area from user application must be protected by critic
|
||||
holding_reg_area[2] += 10;
|
||||
portEXIT_CRITICAL(¶m_lock);
|
||||
|
||||
The stack supports the extended data types when enabled through the the option ``CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND`` in kconfig menu.
|
||||
In this case the mapped data values can be initialized to specific format using :ref:`modbus_api_endianness_conversion`.
|
||||
Please refer to secton :ref:`modbus_mapping_complex_data_types` for more information about data types.
|
||||
|
||||
Example initialization of mapped values:
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include "mbcontroller.h" // for mbcontroller defines and api
|
||||
val_32_arr holding_float_abcd[2] = {0};
|
||||
val_64_arr holding_double_ghefcdab[2] = {0};
|
||||
...
|
||||
// set the Modbus parameter to specific format
|
||||
portENTER_CRITICAL(¶m_lock); // critical section is required if the stack is active
|
||||
mb_set_float_abcd(&holding_float_abcd[0], (float)12345.0);
|
||||
mb_set_float_abcd(&holding_float_abcd[1], (float)12345.0);
|
||||
mb_set_double_ghefcdab(&holding_double_ghefcdab[0], (double)12345.0);
|
||||
portEXIT_CRITICAL(¶m_lock);
|
||||
...
|
||||
// The actual abcd formatted value can be converted to actual float represenatation as below
|
||||
ESP_LOGI("TEST", "Test value abcd: %f", mb_get_float_abcd(&holding_float_abcd[0]));
|
||||
ESP_LOGI("TEST", "Test value abcd: %f", mb_get_float_abcd(&holding_float_abcd[1]));
|
||||
ESP_LOGI("TEST", "Test value ghefcdab: %lf", mb_get_double_ghefcdab(&holding_double_ghefcdab[0]));
|
||||
...
|
||||
|
||||
|
||||
.. _modbus_api_slave_setup_communication_options:
|
||||
|
||||
@ -176,14 +201,14 @@ Example to get event when holding or input registers accessed in the slave:
|
||||
....
|
||||
|
||||
// The function blocks while waiting for register access
|
||||
mb_event_group_t event = mbc_slave_check_event(MB_READ_WRITE_MASK);
|
||||
(void)mbc_slave_check_event(MB_READ_WRITE_MASK);
|
||||
|
||||
// Get information about data accessed from master
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
const char* rw_str = (event & MB_READ_MASK) ? "READ" : "WRITE";
|
||||
const char* rw_str = (reg_info.type & MB_READ_MASK) ? "READ" : "WRITE";
|
||||
|
||||
// Filter events and process them accordingly
|
||||
if (event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||
if (reg_info.type & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||
ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
@ -191,7 +216,7 @@ Example to get event when holding or input registers accessed in the slave:
|
||||
(uint32_t)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(uint32_t)reg_info.size);
|
||||
} else if (event & (MB_EVENT_INPUT_REG_RD)) {
|
||||
} else if (reg_info.type & (MB_EVENT_INPUT_REG_RD)) {
|
||||
ESP_LOGI(TAG, "INPUT %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
|
@ -1 +1 @@
|
||||
esp-docs==0.2.4
|
||||
esp-docs>=1.8,<2.0
|
@ -4,10 +4,11 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_err.h" // for esp_err_t
|
||||
#include "mbc_master.h" // for master interface define
|
||||
#include "esp_modbus_master.h" // for public interface defines
|
||||
#include "esp_err.h" // for esp_err_t
|
||||
#include "mbc_master.h" // for master interface define
|
||||
#include "esp_modbus_master.h" // for public interface defines
|
||||
#include "esp_modbus_callbacks.h" // for callback functions
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_MASTER";
|
||||
|
||||
@ -235,3 +236,281 @@ eMBErrorCode eMBMasterRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
error = master_interface_ptr->master_reg_cb_input(pucRegBuffer, usAddress, usNRegs);
|
||||
return error;
|
||||
}
|
||||
|
||||
// Helper function to set parameter buffer according to its type
|
||||
esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
MB_RETURN_ON_FALSE((src), ESP_ERR_INVALID_STATE, TAG,"incorrect data pointer.");
|
||||
MB_RETURN_ON_FALSE((dest), ESP_ERR_INVALID_STATE, TAG,"incorrect data pointer.");
|
||||
void *pdest = dest;
|
||||
void *psrc = src;
|
||||
|
||||
// Transfer parameter data into value of characteristic
|
||||
switch(param_type)
|
||||
{
|
||||
case PARAM_TYPE_U8:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U8) {
|
||||
*((uint8_t*)pdest) = *((uint8_t*)psrc);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U16:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U16) {
|
||||
*((uint16_t*)pdest) = *((uint16_t*)psrc);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U32:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U32) {
|
||||
*((uint32_t*)pdest) = *((uint32_t*)psrc);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_FLOAT:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_FLOAT) {
|
||||
*((float*)pdest) = *(float*)psrc;
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_ASCII:
|
||||
case PARAM_TYPE_BIN:
|
||||
memcpy((void*)dest, (void*)src, (size_t)param_size);
|
||||
break;
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
|
||||
case PARAM_TYPE_I8_A:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U8_REG) {
|
||||
mb_set_int8_a((val_16_arr *)pdest, (*(int8_t*)psrc));
|
||||
ESP_LOGV(TAG, "Convert uint8 B[%d] 0x%04" PRIx16 " = 0x%04" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I8_B:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U8_REG) {
|
||||
mb_set_int8_b((val_16_arr *)pdest, (int8_t)((*(uint16_t*)psrc) >> 8));
|
||||
ESP_LOGV(TAG, "Convert int8 A[%d] 0x%02" PRIx16 " = 0x%02" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U8_A:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U8_REG) {
|
||||
mb_set_uint8_a((val_16_arr *)pdest, (*(uint8_t*)psrc));
|
||||
ESP_LOGV(TAG, "Convert uint8 A[%d] 0x%02" PRIx16 " = %02" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U8_B:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U8_REG) {
|
||||
uint8_t data = (uint8_t)((*(uint16_t*)psrc) >> 8);
|
||||
mb_set_uint8_b((val_16_arr *)pdest, data);
|
||||
ESP_LOGV(TAG, "Convert uint8 B[%d] 0x%02" PRIx16 " = 0x%02" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I16_AB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I16) {
|
||||
mb_set_int16_ab((val_16_arr *)pdest, *(int16_t*)psrc);
|
||||
ESP_LOGV(TAG, "Convert int16 AB[%d] 0x%04" PRIx16 " = 0x%04" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I16_BA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I16) {
|
||||
mb_set_int16_ba((val_16_arr *)pdest, *(int16_t*)psrc);
|
||||
ESP_LOGV(TAG, "Convert int16 BA[%d] 0x%04" PRIx16 " = 0x%04" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U16_AB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U16) {
|
||||
mb_set_uint16_ab((val_16_arr *)pdest, *(uint16_t*)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint16 AB[%d] 0x%02" PRIx16 " = 0x%02" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U16_BA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U16) {
|
||||
mb_set_uint16_ba((val_16_arr *)pdest, *(uint16_t*)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint16 BA[%d] 0x%02" PRIx16 " = 0x%02" PRIx16, i, *(uint16_t *)psrc, *(uint16_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I32_ABCD:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I32) {
|
||||
mb_set_int32_abcd((val_32_arr *)pdest, *(int32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int32 ABCD[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U32_ABCD:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U32) {
|
||||
mb_set_uint32_abcd((val_32_arr *)pdest, *(uint32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint32 ABCD[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_FLOAT_ABCD:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_FLOAT) {
|
||||
mb_set_float_abcd((val_32_arr *)pdest, *(float *)psrc);
|
||||
ESP_LOGV(TAG, "Convert float ABCD[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I32_CDAB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I32) {
|
||||
mb_set_int32_cdab((val_32_arr *)pdest, *(int32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int32 CDAB[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U32_CDAB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U32) {
|
||||
mb_set_uint32_cdab((val_32_arr *)pdest, *(uint32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint32 CDAB[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_FLOAT_CDAB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_FLOAT) {
|
||||
mb_set_float_cdab((val_32_arr *)pdest, *(float *)psrc);
|
||||
ESP_LOGV(TAG, "Convert float CDAB[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I32_BADC:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I32) {
|
||||
mb_set_int32_badc((val_32_arr *)pdest, *(int32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int32 BADC[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U32_BADC:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U32) {
|
||||
mb_set_uint32_badc((val_32_arr *)pdest, *(uint32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint32 BADC[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_FLOAT_BADC:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_FLOAT) {
|
||||
mb_set_float_badc((val_32_arr *)pdest, *(float *)psrc);
|
||||
ESP_LOGV(TAG, "Convert float BADC[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I32_DCBA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I32) {
|
||||
mb_set_int32_dcba((val_32_arr *)pdest, *(int32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int32 DCBA[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U32_DCBA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U32) {
|
||||
mb_set_uint32_dcba((val_32_arr *)pdest, *(uint32_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint32 DCBA[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_FLOAT_DCBA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_FLOAT) {
|
||||
mb_set_float_dcba((val_32_arr *)pdest, *(float *)psrc);
|
||||
ESP_LOGV(TAG, "Convert float DCBA[%d] 0x%04" PRIx32 " = 0x%04" PRIx32, i, *(uint32_t *)psrc, *(uint32_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I64_ABCDEFGH:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I64) {
|
||||
mb_set_int64_abcdefgh((val_64_arr *)pdest, *(int64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int64 ABCDEFGH[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U64_ABCDEFGH:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U64) {
|
||||
mb_set_uint64_abcdefgh((val_64_arr *)pdest, *(uint64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert double ABCDEFGH[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_DOUBLE_ABCDEFGH:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_DOUBLE) {
|
||||
mb_set_double_abcdefgh((val_64_arr *)pdest, *(double *)psrc);
|
||||
ESP_LOGV(TAG, "Convert double ABCDEFGH[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I64_HGFEDCBA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I64) {
|
||||
mb_set_int64_hgfedcba((val_64_arr *)pdest, *(int64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int64 HGFEDCBA[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U64_HGFEDCBA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U64) {
|
||||
mb_set_uint64_hgfedcba((val_64_arr *)pdest, *(uint64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert double HGFEDCBA[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_DOUBLE_HGFEDCBA:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_DOUBLE) {
|
||||
mb_set_double_hgfedcba((val_64_arr *)pdest, *(double *)psrc);
|
||||
ESP_LOGV(TAG, "Convert double HGFEDCBA[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I64_GHEFCDAB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I64) {
|
||||
mb_set_int64_ghefcdab((val_64_arr *)pdest, *(int64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int64 GHEFCDAB[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U64_GHEFCDAB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U64) {
|
||||
mb_set_uint64_ghefcdab((val_64_arr *)pdest, *(uint64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint64 GHEFCDAB[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_DOUBLE_GHEFCDAB:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_DOUBLE) {
|
||||
mb_set_double_ghefcdab((val_64_arr *)pdest, *(double *)psrc);
|
||||
ESP_LOGV(TAG, "Convert double GHEFCDAB[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_I64_BADCFEHG:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_I64) {
|
||||
mb_set_int64_badcfehg((val_64_arr *)pdest, *(int64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert int64 BADCFEHG[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_U64_BADCFEHG:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_U64) {
|
||||
mb_set_uint64_badcfehg((val_64_arr *)pdest, *(uint64_t *)psrc);
|
||||
ESP_LOGV(TAG, "Convert uint64 BADCFEHG[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_DOUBLE_BADCFEHG:
|
||||
for MB_EACH_ELEM(psrc, pdest, param_size, PARAM_SIZE_DOUBLE) {
|
||||
mb_set_double_badcfehg((val_64_arr *)pdest, *(double *)psrc);
|
||||
ESP_LOGV(TAG, "Convert double BADCFEHG[%d] 0x%" PRIx64 " = 0x%" PRIx64, i, *(uint64_t *)psrc, *(uint64_t *)pdest);
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u).",
|
||||
__FUNCTION__, (unsigned)param_type);
|
||||
err = ESP_ERR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -9,6 +9,11 @@
|
||||
|
||||
#include <inttypes.h> // needs to be included for default system types (such as PRIxx)
|
||||
#include "driver/uart.h" // for UART types
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
#include "mb_endianness_utils.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -43,28 +48,13 @@ extern "C" {
|
||||
#define MB_PAR_INFO_TOUT (10) // Timeout for get parameter info
|
||||
#define MB_PARITY_NONE (UART_PARITY_DISABLE)
|
||||
|
||||
// The Macros below handle the endianness while transfer N byte data into buffer
|
||||
#define _XFER_4_RD(dst, src) { \
|
||||
*(uint8_t *)(dst)++ = *(uint8_t*)(src + 1); \
|
||||
*(uint8_t *)(dst)++ = *(uint8_t*)(src + 0); \
|
||||
*(uint8_t *)(dst)++ = *(uint8_t*)(src + 3); \
|
||||
*(uint8_t *)(dst)++ = *(uint8_t*)(src + 2); \
|
||||
(src) += 4; \
|
||||
}
|
||||
|
||||
// The Macros below handle the endianness while transfer N byte data into buffer (convert from network byte order)
|
||||
#define _XFER_2_RD(dst, src) { \
|
||||
*(uint8_t *)(dst)++ = *(uint8_t *)(src + 1); \
|
||||
*(uint8_t *)(dst)++ = *(uint8_t *)(src + 0); \
|
||||
(src) += 2; \
|
||||
}
|
||||
|
||||
#define _XFER_4_WR(dst, src) { \
|
||||
*(uint8_t *)(dst + 1) = *(uint8_t *)(src)++; \
|
||||
*(uint8_t *)(dst + 0) = *(uint8_t *)(src)++; \
|
||||
*(uint8_t *)(dst + 3) = *(uint8_t *)(src)++; \
|
||||
*(uint8_t *)(dst + 2) = *(uint8_t *)(src)++ ; \
|
||||
}
|
||||
|
||||
#define _XFER_2_WR(dst, src) { \
|
||||
*(uint8_t *)(dst + 1) = *(uint8_t *)(src)++; \
|
||||
*(uint8_t *)(dst + 0) = *(uint8_t *)(src)++; \
|
||||
|
@ -22,6 +22,12 @@ extern "C" {
|
||||
if (!(con)) { ESP_LOGE(TAG, "assert errno:%u, errno_str: !(%s)", (unsigned)errno, strerror(errno)); assert(0 && #con); } \
|
||||
} while (0)
|
||||
|
||||
/*!
|
||||
* \brief The macro to access arrays of elements for type conversion.
|
||||
*/
|
||||
#define MB_EACH_ELEM(psrc, pdest, arr_size, elem_size) \
|
||||
(int i = 0; (i < (arr_size / elem_size)); i++, pdest += elem_size, psrc += elem_size)
|
||||
|
||||
/*!
|
||||
* \brief Modbus descriptor table parameter type defines.
|
||||
*/
|
||||
@ -30,7 +36,40 @@ typedef enum {
|
||||
PARAM_TYPE_U16 = 0x01, /*!< Unsigned 16 */
|
||||
PARAM_TYPE_U32 = 0x02, /*!< Unsigned 32 */
|
||||
PARAM_TYPE_FLOAT = 0x03, /*!< Float type */
|
||||
PARAM_TYPE_ASCII = 0x04 /*!< ASCII type */
|
||||
PARAM_TYPE_ASCII = 0x04, /*!< ASCII type */
|
||||
PARAM_TYPE_BIN = 0x07, /*!< BIN type */
|
||||
PARAM_TYPE_I8_A = 0x0A, /*!< I8 signed integer in high byte of register */
|
||||
PARAM_TYPE_I8_B = 0x0B, /*!< I8 signed integer in low byte of register */
|
||||
PARAM_TYPE_U8_A = 0x0C, /*!< U8 unsigned integer written to hi byte of register */
|
||||
PARAM_TYPE_U8_B = 0x0D, /*!< U8 unsigned integer written to low byte of register */
|
||||
PARAM_TYPE_I16_AB = 0x0E, /*!< I16 signed integer, big endian */
|
||||
PARAM_TYPE_I16_BA = 0x0F, /*!< I16 signed integer, little endian */
|
||||
PARAM_TYPE_U16_AB = 0x10, /*!< U16 unsigned integer, big endian*/
|
||||
PARAM_TYPE_U16_BA = 0x11, /*!< U16 unsigned integer, little endian */
|
||||
PARAM_TYPE_I32_ABCD = 0x12, /*!< I32 ABCD signed integer, big endian */
|
||||
PARAM_TYPE_I32_CDAB = 0x13, /*!< I32 CDAB signed integer, big endian, reversed register order */
|
||||
PARAM_TYPE_I32_BADC = 0x14, /*!< I32 BADC signed integer, little endian, reversed register order */
|
||||
PARAM_TYPE_I32_DCBA = 0x15, /*!< I32 DCBA signed integer, little endian */
|
||||
PARAM_TYPE_U32_ABCD = 0x16, /*!< U32 ABCD unsigned integer, big endian */
|
||||
PARAM_TYPE_U32_CDAB = 0x17, /*!< U32 CDAB unsigned integer, big endian, reversed register order */
|
||||
PARAM_TYPE_U32_BADC = 0x18, /*!< U32 BADC unsigned integer, little endian, reversed register order */
|
||||
PARAM_TYPE_U32_DCBA = 0x19, /*!< U32 DCBA unsigned integer, little endian */
|
||||
PARAM_TYPE_FLOAT_ABCD = 0x1A, /*!< Float ABCD floating point, big endian */
|
||||
PARAM_TYPE_FLOAT_CDAB = 0x1B, /*!< Float CDAB floating point big endian, reversed register order */
|
||||
PARAM_TYPE_FLOAT_BADC = 0x1C, /*!< Float BADC floating point, little endian, reversed register order */
|
||||
PARAM_TYPE_FLOAT_DCBA = 0x1D, /*!< Float DCBA floating point, little endian */
|
||||
PARAM_TYPE_I64_ABCDEFGH = 0x1E, /*!< I64, ABCDEFGH signed integer, big endian */
|
||||
PARAM_TYPE_I64_HGFEDCBA = 0x1F, /*!< I64, HGFEDCBA signed integer, little endian */
|
||||
PARAM_TYPE_I64_GHEFCDAB = 0x20, /*!< I64, GHEFCDAB signed integer, big endian, reversed register order */
|
||||
PARAM_TYPE_I64_BADCFEHG = 0x21, /*!< I64, BADCFEHG signed integer, little endian, reversed register order */
|
||||
PARAM_TYPE_U64_ABCDEFGH = 0x22, /*!< U64, ABCDEFGH unsigned integer, big endian */
|
||||
PARAM_TYPE_U64_HGFEDCBA = 0x23, /*!< U64, HGFEDCBA unsigned integer, little endian */
|
||||
PARAM_TYPE_U64_GHEFCDAB = 0x24, /*!< U64, GHEFCDAB unsigned integer, big endian, reversed register order */
|
||||
PARAM_TYPE_U64_BADCFEHG = 0x25, /*!< U64, BADCFEHG unsigned integer, little endian, reversed register order */
|
||||
PARAM_TYPE_DOUBLE_ABCDEFGH = 0x26, /*!< Double ABCDEFGH floating point, big endian*/
|
||||
PARAM_TYPE_DOUBLE_HGFEDCBA = 0x27, /*!< Double HGFEDCBA floating point, little endian*/
|
||||
PARAM_TYPE_DOUBLE_GHEFCDAB = 0x28, /*!< Double GHEFCDAB floating point, big endian, reversed register order */
|
||||
PARAM_TYPE_DOUBLE_BADCFEHG = 0x29 /*!< Double BADCFEHG floating point, little endian, reversed register order */
|
||||
} mb_descr_type_t;
|
||||
|
||||
/*!
|
||||
@ -38,11 +77,18 @@ typedef enum {
|
||||
*/
|
||||
typedef enum {
|
||||
PARAM_SIZE_U8 = 0x01, /*!< Unsigned 8 */
|
||||
PARAM_SIZE_U8_REG = 0x02, /*!< Unsigned 8, register value */
|
||||
PARAM_SIZE_I8_REG = 0x02, /*!< Signed 8, register value */
|
||||
PARAM_SIZE_I16 = 0x02, /*!< Unsigned 16 */
|
||||
PARAM_SIZE_U16 = 0x02, /*!< Unsigned 16 */
|
||||
PARAM_SIZE_I32 = 0x04, /*!< Signed 32 */
|
||||
PARAM_SIZE_U32 = 0x04, /*!< Unsigned 32 */
|
||||
PARAM_SIZE_FLOAT = 0x04, /*!< Float size */
|
||||
PARAM_SIZE_ASCII = 0x08, /*!< ASCII size */
|
||||
PARAM_SIZE_FLOAT = 0x04, /*!< Float 32 size */
|
||||
PARAM_SIZE_ASCII = 0x08, /*!< ASCII size default*/
|
||||
PARAM_SIZE_ASCII24 = 0x18, /*!< ASCII24 size */
|
||||
PARAM_SIZE_I64 = 0x08, /*!< Signed integer 64 size */
|
||||
PARAM_SIZE_U64 = 0x08, /*!< Unsigned integer 64 size */
|
||||
PARAM_SIZE_DOUBLE = 0x08, /*!< Double 64 size */
|
||||
PARAM_MAX_SIZE
|
||||
} mb_descr_size_t;
|
||||
|
||||
@ -259,6 +305,22 @@ esp_err_t mbc_master_get_parameter(uint16_t cid, char* name, uint8_t* value, uin
|
||||
*/
|
||||
esp_err_t mbc_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uint8_t *type);
|
||||
|
||||
/**
|
||||
* @brief The helper function to set data of parameters according to its type
|
||||
*
|
||||
* @param[in] dest the destination address of the parameter
|
||||
* @param[in] src the source address of the parameter
|
||||
* @param[out] param_type type of parameter from data dictionary
|
||||
* @param[out] param_size the storage size of the characteristic (in bytes).
|
||||
* Describes the size of data to keep into data instance during mapping.
|
||||
*
|
||||
* @return
|
||||
* - esp_err_t ESP_OK - request was successful and value was saved in the slave device registers
|
||||
* - esp_err_t ESP_ERR_INVALID_ARG - invalid argument of function or parameter descriptor
|
||||
* - esp_err_t ESP_ERR_NOT_SUPPORTED - the request command is not supported by slave
|
||||
*/
|
||||
esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
556
freemodbus/common/include/mb_endianness_utils.h
Normal file
556
freemodbus/common/include/mb_endianness_utils.h
Normal file
@ -0,0 +1,556 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Defines the constant values based on native compiler byte ordering.
|
||||
*/
|
||||
#define MB_BO16_0 0
|
||||
#define MB_BO16_1 1
|
||||
|
||||
#define MB_BO32_0 0
|
||||
#define MB_BO32_1 1
|
||||
#define MB_BO32_2 2
|
||||
#define MB_BO32_3 3
|
||||
|
||||
#define MB_BO64_0 0
|
||||
#define MB_BO64_1 1
|
||||
#define MB_BO64_2 2
|
||||
#define MB_BO64_3 3
|
||||
#define MB_BO64_4 4
|
||||
#define MB_BO64_5 5
|
||||
#define MB_BO64_6 6
|
||||
#define MB_BO64_7 7
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The sized array types used for mapping of extended values
|
||||
*/
|
||||
typedef uint8_t val_16_arr[2];
|
||||
typedef uint8_t val_32_arr[4];
|
||||
typedef uint8_t val_64_arr[8];
|
||||
|
||||
/**
|
||||
* @brief Get int8_t (low byte) value represenatation from register
|
||||
*
|
||||
* @return
|
||||
* - int8_t value of converted from register value
|
||||
*/
|
||||
int8_t mb_get_int8_a(val_16_arr *pi16);
|
||||
|
||||
/**
|
||||
* @brief Set i8 value to the register value pointed by pi16
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the actual hex value of the register
|
||||
*/
|
||||
uint16_t mb_set_int8_a(val_16_arr *pi16, int8_t i8);
|
||||
|
||||
/**
|
||||
* @brief Get int8_t (high byte) value from the register value pointed by pi16
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the actual hex value of the register
|
||||
*/
|
||||
int8_t mb_get_int8_b(val_16_arr *pi16);
|
||||
|
||||
/**
|
||||
* @brief Set i8 (high byte) value from the register value pointed by pi16
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the actual hex value of the register
|
||||
*/
|
||||
uint16_t mb_set_int8_b(val_16_arr *pi16, int8_t i8);
|
||||
|
||||
/**
|
||||
* @brief Get uint8_t (low byte) value represenatation from register poined by pu16
|
||||
*
|
||||
* @return
|
||||
* - uint8_t the value of converted from register value
|
||||
*/
|
||||
uint8_t mb_get_uint8_a(val_16_arr *pu16);
|
||||
|
||||
/**
|
||||
* @brief Set u8 (low byte) value into the register value pointed by pu16
|
||||
*
|
||||
* @return
|
||||
* - uint16_t the value which represents the actual hex value of the register
|
||||
*/
|
||||
uint16_t mb_set_uint8_a(val_16_arr *pu16, uint8_t u8);
|
||||
|
||||
/**
|
||||
* @brief Get uint8_t (high byte) value from the register value pointed by pu16
|
||||
*
|
||||
* @return
|
||||
* - uint16_t the value which represents the actual hex value of the register
|
||||
*/
|
||||
uint8_t mb_get_uint8_b(val_16_arr *pu16);
|
||||
|
||||
/**
|
||||
* @brief Set u8 (high byte) value into the register value pointed by pu16
|
||||
*
|
||||
* @return
|
||||
* - uint16_t the value which represents the actual hex value of the register
|
||||
*/
|
||||
uint16_t mb_set_uint8_b(val_16_arr *pu16, uint8_t u8);
|
||||
|
||||
/**
|
||||
* @brief Get int16_t value from the register value pointed by pu16 with ab endianness
|
||||
*
|
||||
* @return
|
||||
* - int16_t the value which represents the converted value from register
|
||||
*/
|
||||
int16_t mb_get_int16_ab(val_16_arr *pi16);
|
||||
|
||||
/**
|
||||
* @brief Set i16 value to the register pointed by pi16 with ab endianness
|
||||
*
|
||||
* @return
|
||||
* - int16_t the value which represents the converted value from register
|
||||
*/
|
||||
uint16_t mb_set_int16_ab(val_16_arr *pi16, int16_t i16);
|
||||
|
||||
/**
|
||||
* @brief Get uint16_t value from the register value pointed by pu16 with ab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the converted register value
|
||||
*/
|
||||
uint16_t mb_get_uint16_ab(val_16_arr *pu16);
|
||||
|
||||
/**
|
||||
* @brief Set u16 value to the register pointed by pu16 with ab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the converted value from register
|
||||
*/
|
||||
uint16_t mb_set_uint16_ab(val_16_arr *pu16, uint16_t u16);
|
||||
|
||||
/**
|
||||
* @brief Get int16_t value from the register value pointed by pu16 with ba endianness
|
||||
*
|
||||
* @return
|
||||
* - int16_t value which represents the converted register value
|
||||
*/
|
||||
int16_t mb_get_int16_ba(val_16_arr *pi16);
|
||||
|
||||
/**
|
||||
* @brief Set i16 value to the register pointed by pi16 with ba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the converted value from register
|
||||
*/
|
||||
uint16_t mb_set_int16_ba(val_16_arr *pi16, int16_t i16);
|
||||
|
||||
/**
|
||||
* @brief Get uint16_t value from the register value pointed by pu16 with ba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the converted register value
|
||||
*/
|
||||
uint16_t mb_get_uint16_ba(val_16_arr *pu16);
|
||||
|
||||
/**
|
||||
* @brief Set u16 value to the register pointed by pu16 with ba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint16_t value which represents the converted value from register
|
||||
*/
|
||||
uint16_t mb_set_uint16_ba(val_16_arr *pu16, uint16_t u16);
|
||||
|
||||
/**
|
||||
* @brief Get int32_t value from the register value pointed by pi32 with abcd endianness
|
||||
*
|
||||
* @return
|
||||
* - int32_t value which represents the converted register value
|
||||
*/
|
||||
int32_t mb_get_int32_abcd(val_32_arr *pi32);
|
||||
|
||||
/**
|
||||
* @brief Set i32 value to the register pointed by pi32 with abcd endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_int32_abcd(val_32_arr *pi32, int32_t i32);
|
||||
|
||||
/**
|
||||
* @brief Get uint32_t value from the register value pointed by pu32 with abcd endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted register value
|
||||
*/
|
||||
uint32_t mb_get_uint32_abcd(val_32_arr *pu32);
|
||||
|
||||
/**
|
||||
* @brief Set u32 value to the register pointed by pu32 with abcd endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_uint32_abcd(val_32_arr *pu32, uint32_t u32);
|
||||
|
||||
/**
|
||||
* @brief Get int32_t value from the register value pointed by pi32 with badc endianness
|
||||
*
|
||||
* @return
|
||||
* - int32_t value which represents the converted register value
|
||||
*/
|
||||
int32_t mb_get_int32_badc(val_32_arr *pi32);
|
||||
|
||||
/**
|
||||
* @brief Set i32 value to the register pointed by pi32 with badc endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_int32_badc(val_32_arr *pi32, int32_t i32);
|
||||
|
||||
/**
|
||||
* @brief Get uint32_t value from the register value pointed by pu32 with badc endianness
|
||||
*
|
||||
* @return
|
||||
* - unt32_t value which represents the converted register value
|
||||
*/
|
||||
uint32_t mb_get_uint32_badc(val_32_arr *pu32);
|
||||
|
||||
/**
|
||||
* @brief Set u32 value to the register pointed by pu32 with badc endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_uint32_badc(val_32_arr *pu32, uint32_t u32);
|
||||
|
||||
/**
|
||||
* @brief Get int32_t value from the register value pointed by pi32 with cdab endianness
|
||||
*
|
||||
* @return
|
||||
* - int32_t value which represents the converted register value
|
||||
*/
|
||||
int32_t mb_get_int32_cdab(val_32_arr *pi32);
|
||||
|
||||
/**
|
||||
* @brief Set i32 value to the register pointed by pi32 with cdab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_int32_cdab(val_32_arr *pi32, int32_t i32);
|
||||
|
||||
/**
|
||||
* @brief Get uint32_t value from the register value pointed by pu32 with cdab endianness
|
||||
*
|
||||
* @return
|
||||
* - int32_t value which represents the converted register value
|
||||
*/
|
||||
uint32_t mb_get_uint32_cdab(val_32_arr *pu32);
|
||||
|
||||
/**
|
||||
* @brief Set u32 value to the register pointed by pu32 with cdab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_uint32_cdab(val_32_arr *pu32, uint32_t u32);
|
||||
|
||||
/**
|
||||
* @brief Get int32_t value from the register value pointed by pi32 with dcba endianness
|
||||
*
|
||||
* @return
|
||||
* - int32_t value which represents the converted register value
|
||||
*/
|
||||
int32_t mb_get_int32_dcba(val_32_arr *pi32);
|
||||
|
||||
/**
|
||||
* @brief Set i32 value to the register pointed by pi32 with dcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_int32_dcba(val_32_arr *pi32, int32_t i32);
|
||||
|
||||
/**
|
||||
* @brief Get uint32_t value from the register value pointed by pu32 with dcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted register value
|
||||
*/
|
||||
uint32_t mb_get_uint32_dcba(val_32_arr *pu32);
|
||||
|
||||
/**
|
||||
* @brief Set u32 value to the register pointed by pu32 with dcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_uint32_dcba(val_32_arr *pu32, uint32_t u32);
|
||||
|
||||
/**
|
||||
* @brief Get float value from the register pointed by pf with abcd endianness
|
||||
*
|
||||
* @return
|
||||
* - float value which represents the converted register value
|
||||
*/
|
||||
float mb_get_float_abcd(val_32_arr *pf);
|
||||
|
||||
/**
|
||||
* @brief Set f value to the register pointed by pf with abcd endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_float_abcd(val_32_arr *pf, float f);
|
||||
|
||||
/**
|
||||
* @brief Get float value from the register pointed by pf with badc endianness
|
||||
*
|
||||
* @return
|
||||
* - float value which represents the converted register value
|
||||
*/
|
||||
float mb_get_float_badc(val_32_arr *pf);
|
||||
|
||||
/**
|
||||
* @brief Set f value to the register pointed by pf with badc endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_float_badc(val_32_arr *pf, float f);
|
||||
|
||||
/**
|
||||
* @brief Get float value from the register pointed by pf with cdab endianness
|
||||
*
|
||||
* @return
|
||||
* - float value which represents the converted register value
|
||||
*/
|
||||
float mb_get_float_cdab(val_32_arr *pf);
|
||||
|
||||
/**
|
||||
* @brief Set f value to the register pointed by pf with cdab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_float_cdab(val_32_arr *pf, float f);
|
||||
|
||||
/**
|
||||
* @brief Get float value from the register pointed by pf with dcba endianness
|
||||
*
|
||||
* @return
|
||||
* - float value which represents the converted register value
|
||||
*/
|
||||
float mb_get_float_dcba(val_32_arr *pf);
|
||||
|
||||
/**
|
||||
* @brief Set f value to the register pointed by pf with dcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint32_t value which represents the converted value from register
|
||||
*/
|
||||
uint32_t mb_set_float_dcba(val_32_arr *pf, float f);
|
||||
|
||||
/**
|
||||
* @brief Get double value from the register pointed by pd with abcdefgh endianness
|
||||
*
|
||||
* @return
|
||||
* - double value which represents the converted register value
|
||||
*/
|
||||
double mb_get_double_abcdefgh(val_64_arr *pd);
|
||||
|
||||
/**
|
||||
* @brief Set d value to the register pointed by pd with abcdefgh endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_double_abcdefgh(val_64_arr *pd, double d);
|
||||
|
||||
/**
|
||||
* @brief Get double value from the register pointed by pd with hgfedcba endianness
|
||||
*
|
||||
* @return
|
||||
* - double value which represents the converted register value
|
||||
*/
|
||||
double mb_get_double_hgfedcba(val_64_arr *pd);
|
||||
|
||||
/**
|
||||
* @brief Set d value to the register pointed by pd with hgfedcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_double_hgfedcba(val_64_arr *pd, double d);
|
||||
|
||||
/**
|
||||
* @brief Get double value from the register pointed by pd with ghefcdab endianness
|
||||
*
|
||||
* @return
|
||||
* - double value which represents the converted register value
|
||||
*/
|
||||
double mb_get_double_ghefcdab(val_64_arr *pd);
|
||||
|
||||
/**
|
||||
* @brief Set d value to the register pointed by pd with ghefcdab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_double_ghefcdab(val_64_arr *pd, double d);
|
||||
|
||||
/**
|
||||
* @brief Get double value from the register pointed by pd with badcfehg endianness
|
||||
*
|
||||
* @return
|
||||
* - double value which represents the converted register value
|
||||
*/
|
||||
double mb_get_double_badcfehg(val_64_arr *pd);
|
||||
|
||||
/**
|
||||
* @brief Set d value to the register pointed by pd with badcfehg endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_double_badcfehg(val_64_arr *pd, double d);
|
||||
|
||||
/**
|
||||
* @brief Get int64_t value from the register pointed by pi64 with abcdefgh endianness
|
||||
*
|
||||
* @return
|
||||
* - int64_t value which represents the converted register value
|
||||
*/
|
||||
int64_t mb_get_int64_abcdefgh(val_64_arr *pi64);
|
||||
|
||||
/**
|
||||
* @brief Set i value to the register pointed by pi with abcdefgh endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_int64_abcdefgh(val_64_arr *pi, int64_t i);
|
||||
|
||||
/**
|
||||
* @brief Get int64_t value from the register pointed by pi64 with ghefcdab endianness
|
||||
*
|
||||
* @return
|
||||
* - int64_t value which represents the converted register value
|
||||
*/
|
||||
int64_t mb_get_int64_ghefcdab(val_64_arr *pi64);
|
||||
|
||||
/**
|
||||
* @brief Set i value to the register pointed by pi with ghefcdab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_int64_ghefcdab(val_64_arr *pi, int64_t i);
|
||||
|
||||
/**
|
||||
* @brief Get int64_t value from the register pointed by pi64 with hgfedcba endianness
|
||||
*
|
||||
* @return
|
||||
* - int64_t value which represents the converted register value
|
||||
*/
|
||||
int64_t mb_get_int64_hgfedcba(val_64_arr *pi64);
|
||||
|
||||
/**
|
||||
* @brief Set i value to the register pointed by pi with hgfedcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_int64_hgfedcba(val_64_arr *pi, int64_t i);
|
||||
|
||||
/**
|
||||
* @brief Get int64_t value from the register pointed by pi64 with badcfehg endianness
|
||||
*
|
||||
* @return
|
||||
* - int64_t value which represents the converted register value
|
||||
*/
|
||||
int64_t mb_get_int64_badcfehg(val_64_arr *pi64);
|
||||
|
||||
/**
|
||||
* @brief Set i value to the register pointed by pi with badcfehg endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_int64_badcfehg(val_64_arr *pi, int64_t i);
|
||||
|
||||
/**
|
||||
* @brief Get uint64_t value from the register pointed by pui with abcdefgh endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted register value
|
||||
*/
|
||||
uint64_t mb_get_uint64_abcdefgh(val_64_arr *pui);
|
||||
|
||||
/**
|
||||
* @brief Set ui value to the register pointed by pi with abcdefgh endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_uint64_abcdefgh(val_64_arr *pui, uint64_t ui);
|
||||
|
||||
/**
|
||||
* @brief Get uint64_t value from the register pointed by pui with hgfedcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted register value
|
||||
*/
|
||||
uint64_t mb_get_uint64_hgfedcba(val_64_arr *pui);
|
||||
|
||||
/**
|
||||
* @brief Set ui value to the register pointed by pui with hgfedcba endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_uint64_hgfedcba(val_64_arr *pui, uint64_t ui);
|
||||
|
||||
/**
|
||||
* @brief Get uint64_t value from the register pointed by pui with ghefcdab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted register value
|
||||
*/
|
||||
uint64_t mb_get_uint64_ghefcdab(val_64_arr *pui);
|
||||
|
||||
/**
|
||||
* @brief Set ui value to the register pointed by pui with ghefcdab endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_uint64_ghefcdab(val_64_arr *pui, uint64_t ui);
|
||||
|
||||
/**
|
||||
* @brief Get uint64_t value from the register pointed by pui with badcfehg endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted register value
|
||||
*/
|
||||
uint64_t mb_get_uint64_badcfehg(val_64_arr *pui);
|
||||
|
||||
/**
|
||||
* @brief Set ui value to the register pointed by pui with badcfehg endianness
|
||||
*
|
||||
* @return
|
||||
* - uint64_t value which represents the converted value from register
|
||||
*/
|
||||
uint64_t mb_set_uint64_badcfehg(val_64_arr *pui, uint64_t ui);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
683
freemodbus/common/mb_endianness_utils.c
Normal file
683
freemodbus/common/mb_endianness_utils.c
Normal file
@ -0,0 +1,683 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mb_endianness_utils.h"
|
||||
|
||||
#define INLINE inline __attribute__((always_inline))
|
||||
|
||||
static INLINE int16_t mb_get_int16_generic(int n0, int n1, val_16_arr *psrc)
|
||||
{
|
||||
val_16_arr *pv = psrc;
|
||||
union {
|
||||
val_16_arr arr;
|
||||
int16_t value;
|
||||
} bov;
|
||||
bov.arr[n0] = (*pv)[MB_BO16_0];
|
||||
bov.arr[n1] = (*pv)[MB_BO16_1];
|
||||
return (bov.value);
|
||||
}
|
||||
|
||||
static INLINE uint16_t mb_get_uint16_generic(int n0, int n1, val_16_arr *psrc)
|
||||
{
|
||||
val_16_arr *pv = psrc;
|
||||
union {
|
||||
val_16_arr arr;
|
||||
uint16_t value;
|
||||
} bov;
|
||||
bov.arr[n0] = (*pv)[MB_BO16_0];
|
||||
bov.arr[n1] = (*pv)[MB_BO16_1];
|
||||
return (bov.value);
|
||||
}
|
||||
|
||||
static INLINE uint16_t mb_set_uint16_generic(int n0, int n1, val_16_arr *pdest, uint16_t val)
|
||||
{
|
||||
val_16_arr *pv = pdest;
|
||||
union {
|
||||
val_16_arr arr;
|
||||
uint16_t value;
|
||||
} bov;
|
||||
bov.value = val;
|
||||
(*pv)[MB_BO16_0] = bov.arr[n0];
|
||||
(*pv)[MB_BO16_1] = bov.arr[n1];
|
||||
return (*((uint16_t *)pv));
|
||||
}
|
||||
|
||||
static INLINE int16_t mb_set_int16_generic(int n0, int n1, val_16_arr *pdest, int16_t val)
|
||||
{
|
||||
val_16_arr *pv = pdest;
|
||||
union {
|
||||
val_16_arr arr;
|
||||
int16_t value;
|
||||
} bov;
|
||||
bov.value = val;
|
||||
(*pv)[MB_BO16_0] = bov.arr[n0];
|
||||
(*pv)[MB_BO16_1] = bov.arr[n1];
|
||||
return (*((uint16_t *)pv));
|
||||
}
|
||||
|
||||
static INLINE uint32_t mb_get_uint32_generic(int n0, int n1, int n2, int n3, val_32_arr *psrc)
|
||||
{
|
||||
val_32_arr *pv = psrc;
|
||||
union {
|
||||
val_32_arr arr;
|
||||
uint32_t value;
|
||||
} bov;
|
||||
bov.arr[n0] = (*pv)[MB_BO32_0];
|
||||
bov.arr[n1] = (*pv)[MB_BO32_1];
|
||||
bov.arr[n2] = (*pv)[MB_BO32_2];
|
||||
bov.arr[n3] = (*pv)[MB_BO32_3];
|
||||
return (bov.value);
|
||||
}
|
||||
|
||||
static INLINE int32_t mb_get_int32_generic(int n0, int n1, int n2, int n3, val_32_arr *psrc)
|
||||
{
|
||||
val_32_arr *pv = psrc;
|
||||
union {
|
||||
val_32_arr arr;
|
||||
int32_t value;
|
||||
} bov;
|
||||
bov.arr[n0] = (*pv)[MB_BO32_0];
|
||||
bov.arr[n1] = (*pv)[MB_BO32_1];
|
||||
bov.arr[n2] = (*pv)[MB_BO32_2];
|
||||
bov.arr[n3] = (*pv)[MB_BO32_3];
|
||||
return (bov.value);
|
||||
}
|
||||
|
||||
static INLINE float mb_get_float_generic(int n0, int n1, int n2, int n3, val_32_arr *psrc)
|
||||
{
|
||||
val_32_arr *pv = psrc;
|
||||
union {
|
||||
val_32_arr arr;
|
||||
float value;
|
||||
} bov;
|
||||
bov.arr[n0] = (*pv)[MB_BO32_0];
|
||||
bov.arr[n1] = (*pv)[MB_BO32_1];
|
||||
bov.arr[n2] = (*pv)[MB_BO32_2];
|
||||
bov.arr[n3] = (*pv)[MB_BO32_3];
|
||||
return (bov.value);
|
||||
}
|
||||
|
||||
static INLINE uint32_t mb_set_int32_generic(int n0, int n1, int n2, int n3, val_32_arr *pdest, int32_t val)
|
||||
{
|
||||
val_32_arr *pv = pdest;
|
||||
union {
|
||||
val_32_arr arr;
|
||||
int32_t value;
|
||||
} bov;
|
||||
bov.value = val;
|
||||
(*pv)[MB_BO32_0] = bov.arr[n0];
|
||||
(*pv)[MB_BO32_1] = bov.arr[n1];
|
||||
(*pv)[MB_BO32_2] = bov.arr[n2];
|
||||
(*pv)[MB_BO32_3] = bov.arr[n3];
|
||||
return (*((uint32_t *)pv));
|
||||
}
|
||||
|
||||
static INLINE uint32_t mb_set_uint32_generic(int n0, int n1, int n2, int n3, val_32_arr *pdest, uint32_t val)
|
||||
{
|
||||
val_32_arr *pv = pdest;
|
||||
union {
|
||||
val_32_arr arr;
|
||||
uint32_t value;
|
||||
} bov;
|
||||
bov.value = val;
|
||||
(*pv)[MB_BO32_0] = bov.arr[n0];
|
||||
(*pv)[MB_BO32_1] = bov.arr[n1];
|
||||
(*pv)[MB_BO32_2] = bov.arr[n2];
|
||||
(*pv)[MB_BO32_3] = bov.arr[n3];
|
||||
return (*((uint32_t *)pv));
|
||||
}
|
||||
|
||||
static INLINE uint32_t mb_set_float_generic(int n0, int n1, int n2, int n3, val_32_arr *pdest, float val)
|
||||
{
|
||||
val_32_arr *pv = pdest;
|
||||
union {
|
||||
val_32_arr arr;
|
||||
float value;
|
||||
} bov;
|
||||
bov.value = val;
|
||||
(*pv)[MB_BO32_0] = bov.arr[n0];
|
||||
(*pv)[MB_BO32_1] = bov.arr[n1];
|
||||
(*pv)[MB_BO32_2] = bov.arr[n2];
|
||||
(*pv)[MB_BO32_3] = bov.arr[n3];
|
||||
return (*((uint32_t *)pv));
|
||||
}
|
||||
|
||||
static INLINE int64_t mb_get_int64_generic(int n0, int n1, int n2, int n3, int n4, int n5, int n6, int n7, val_64_arr *psrc)
|
||||
{
|
||||
val_64_arr *pv64 = psrc;
|
||||
union {
|
||||
val_64_arr arr;
|
||||
int64_t value;
|
||||
} bo64;
|
||||
bo64.arr[n0] = (*pv64)[MB_BO64_0];
|
||||
bo64.arr[n1] = (*pv64)[MB_BO64_1];
|
||||
bo64.arr[n2] = (*pv64)[MB_BO64_2];
|
||||
bo64.arr[n3] = (*pv64)[MB_BO64_3];
|
||||
bo64.arr[n4] = (*pv64)[MB_BO64_4];
|
||||
bo64.arr[n5] = (*pv64)[MB_BO64_5];
|
||||
bo64.arr[n6] = (*pv64)[MB_BO64_6];
|
||||
bo64.arr[n7] = (*pv64)[MB_BO64_7];
|
||||
return (bo64.value);
|
||||
}
|
||||
|
||||
static INLINE uint64_t mb_get_uint64_generic(int n0, int n1, int n2, int n3, int n4, int n5, int n6, int n7, val_64_arr *psrc)
|
||||
{
|
||||
val_64_arr *pv64 = psrc;
|
||||
union {
|
||||
val_64_arr arr;
|
||||
uint64_t value;
|
||||
} bo64;
|
||||
bo64.arr[n0] = (*pv64)[MB_BO64_0];
|
||||
bo64.arr[n1] = (*pv64)[MB_BO64_1];
|
||||
bo64.arr[n2] = (*pv64)[MB_BO64_2];
|
||||
bo64.arr[n3] = (*pv64)[MB_BO64_3];
|
||||
bo64.arr[n4] = (*pv64)[MB_BO64_4];
|
||||
bo64.arr[n5] = (*pv64)[MB_BO64_5];
|
||||
bo64.arr[n6] = (*pv64)[MB_BO64_6];
|
||||
bo64.arr[n7] = (*pv64)[MB_BO64_7];
|
||||
return (bo64.value);
|
||||
}
|
||||
|
||||
static INLINE double mb_get_double_generic(int n0, int n1, int n2, int n3, int n4, int n5, int n6, int n7, val_64_arr *psrc)
|
||||
{
|
||||
val_64_arr *pv64 = psrc;
|
||||
union {
|
||||
val_64_arr arr;
|
||||
double value;
|
||||
} bo64;
|
||||
bo64.arr[n0] = (*pv64)[MB_BO64_0];
|
||||
bo64.arr[n1] = (*pv64)[MB_BO64_1];
|
||||
bo64.arr[n2] = (*pv64)[MB_BO64_2];
|
||||
bo64.arr[n3] = (*pv64)[MB_BO64_3];
|
||||
bo64.arr[n4] = (*pv64)[MB_BO64_4];
|
||||
bo64.arr[n5] = (*pv64)[MB_BO64_5];
|
||||
bo64.arr[n6] = (*pv64)[MB_BO64_6];
|
||||
bo64.arr[n7] = (*pv64)[MB_BO64_7];
|
||||
return (bo64.value);
|
||||
}
|
||||
|
||||
static INLINE uint64_t mb_set_int64_generic(int n0, int n1, int n2, int n3, int n4, int n5, int n6, int n7, val_64_arr *pdest, int64_t val)
|
||||
{
|
||||
val_64_arr *pv = pdest;
|
||||
union {
|
||||
val_64_arr arr;
|
||||
int64_t value;
|
||||
} bo64;
|
||||
bo64.value = val;
|
||||
(*pv)[MB_BO64_0] = bo64.arr[n0];
|
||||
(*pv)[MB_BO64_1] = bo64.arr[n1];
|
||||
(*pv)[MB_BO64_2] = bo64.arr[n2];
|
||||
(*pv)[MB_BO64_3] = bo64.arr[n3];
|
||||
(*pv)[MB_BO64_4] = bo64.arr[n4];
|
||||
(*pv)[MB_BO64_5] = bo64.arr[n5];
|
||||
(*pv)[MB_BO64_6] = bo64.arr[n6];
|
||||
(*pv)[MB_BO64_7] = bo64.arr[n7];
|
||||
return (*((uint64_t *)pv));
|
||||
}
|
||||
|
||||
static INLINE uint64_t mb_set_uint64_generic(int n0, int n1, int n2, int n3, int n4, int n5, int n6, int n7, val_64_arr *pdest, uint64_t val)
|
||||
{
|
||||
val_64_arr *pv = pdest;
|
||||
union {
|
||||
val_64_arr arr;
|
||||
uint64_t value;
|
||||
} bo64;
|
||||
bo64.value = val;
|
||||
(*pv)[MB_BO64_0] = bo64.arr[n0];
|
||||
(*pv)[MB_BO64_1] = bo64.arr[n1];
|
||||
(*pv)[MB_BO64_2] = bo64.arr[n2];
|
||||
(*pv)[MB_BO64_3] = bo64.arr[n3];
|
||||
(*pv)[MB_BO64_4] = bo64.arr[n4];
|
||||
(*pv)[MB_BO64_5] = bo64.arr[n5];
|
||||
(*pv)[MB_BO64_6] = bo64.arr[n6];
|
||||
(*pv)[MB_BO64_7] = bo64.arr[n7];
|
||||
return (*((uint64_t *)pv));
|
||||
}
|
||||
|
||||
static INLINE uint64_t mb_set_double_generic(int n0, int n1, int n2, int n3, int n4, int n5, int n6, int n7, val_64_arr *pdest, double val)
|
||||
{
|
||||
val_64_arr *pv = pdest;
|
||||
union {
|
||||
val_64_arr arr;
|
||||
double value;
|
||||
} bo64;
|
||||
bo64.value = val;
|
||||
(*pv)[MB_BO64_0] = bo64.arr[n0];
|
||||
(*pv)[MB_BO64_1] = bo64.arr[n1];
|
||||
(*pv)[MB_BO64_2] = bo64.arr[n2];
|
||||
(*pv)[MB_BO64_3] = bo64.arr[n3];
|
||||
(*pv)[MB_BO64_4] = bo64.arr[n4];
|
||||
(*pv)[MB_BO64_5] = bo64.arr[n5];
|
||||
(*pv)[MB_BO64_6] = bo64.arr[n6];
|
||||
(*pv)[MB_BO64_7] = bo64.arr[n7];
|
||||
return (*((uint64_t *)pv));
|
||||
}
|
||||
|
||||
int8_t mb_get_int8_a(pi16)
|
||||
val_16_arr *pi16;
|
||||
{
|
||||
return((int8_t)(*pi16)[MB_BO16_0]);
|
||||
}
|
||||
|
||||
uint16_t mb_set_int8_a(pi16, i8)
|
||||
val_16_arr *pi16;
|
||||
int8_t i8;
|
||||
{
|
||||
(*pi16)[MB_BO16_0] = (uint8_t)i8;
|
||||
(*pi16)[MB_BO16_1] = 0;
|
||||
return (*((uint16_t *)pi16));
|
||||
}
|
||||
|
||||
int8_t mb_get_int8_b(pi16)
|
||||
val_16_arr *pi16;
|
||||
{
|
||||
return((int8_t)(*pi16)[MB_BO16_1]);
|
||||
}
|
||||
|
||||
uint16_t mb_set_int8_b(pi16, i8)
|
||||
val_16_arr *pi16;
|
||||
int8_t i8;
|
||||
{
|
||||
(*pi16)[MB_BO16_0] = 0;
|
||||
(*pi16)[MB_BO16_1] = (int8_t)i8;
|
||||
return (*((uint16_t *)pi16));
|
||||
}
|
||||
|
||||
uint8_t mb_get_uint8_a(pu16)
|
||||
val_16_arr *pu16;
|
||||
{
|
||||
return((uint8_t)(*pu16)[MB_BO16_0]);
|
||||
}
|
||||
|
||||
uint16_t mb_set_uint8_a(pu16, u8)
|
||||
val_16_arr *pu16;
|
||||
uint8_t u8;
|
||||
{
|
||||
(*pu16)[MB_BO16_0] = (uint8_t)u8;
|
||||
(*pu16)[MB_BO16_1] = 0;
|
||||
return (*((uint16_t *)pu16));
|
||||
}
|
||||
|
||||
uint8_t mb_get_uint8_b(pu16)
|
||||
val_16_arr *pu16;
|
||||
{
|
||||
return((uint8_t)(*pu16)[MB_BO16_1]);
|
||||
}
|
||||
|
||||
uint16_t mb_set_uint8_b(pu16, u8)
|
||||
val_16_arr *pu16;
|
||||
uint8_t u8;
|
||||
{
|
||||
(*pu16)[MB_BO16_0] = 0;
|
||||
(*pu16)[MB_BO16_1] = (uint8_t)u8;
|
||||
return (*((uint16_t *)pu16));
|
||||
}
|
||||
|
||||
int16_t mb_get_int16_ab(pi16)
|
||||
val_16_arr *pi16;
|
||||
{
|
||||
return mb_get_int16_generic(0, 1, pi16);
|
||||
}
|
||||
|
||||
uint16_t mb_set_int16_ab(pi16, i16)
|
||||
val_16_arr *pi16;
|
||||
int16_t i16;
|
||||
{
|
||||
return mb_set_int16_generic(0, 1, pi16, i16);
|
||||
}
|
||||
|
||||
uint16_t mb_get_uint16_ab(pu16)
|
||||
val_16_arr *pu16;
|
||||
{
|
||||
return mb_get_uint16_generic(0, 1, pu16);
|
||||
}
|
||||
|
||||
uint16_t mb_set_uint16_ab(pu16, u16)
|
||||
val_16_arr *pu16;
|
||||
uint16_t u16;
|
||||
{
|
||||
return mb_set_uint16_generic(0, 1, pu16, u16);
|
||||
}
|
||||
|
||||
int16_t mb_get_int16_ba(pi16)
|
||||
val_16_arr *pi16;
|
||||
{
|
||||
return mb_get_int16_generic(1, 0, pi16);
|
||||
}
|
||||
|
||||
uint16_t mb_set_int16_ba(pi16, i16)
|
||||
val_16_arr *pi16;
|
||||
int16_t i16;
|
||||
{
|
||||
return mb_set_int16_generic(1, 0, pi16, i16);
|
||||
}
|
||||
|
||||
uint16_t mb_get_uint16_ba(pu16)
|
||||
val_16_arr *pu16;
|
||||
{
|
||||
return mb_get_int16_generic(1, 0, pu16);
|
||||
}
|
||||
|
||||
uint16_t mb_set_uint16_ba(pu16, u16)
|
||||
val_16_arr *pu16;
|
||||
uint16_t u16;
|
||||
{
|
||||
return mb_set_int16_generic(1, 0, pu16, u16);
|
||||
}
|
||||
|
||||
int32_t mb_get_int32_abcd(pi32)
|
||||
val_32_arr *pi32;
|
||||
{
|
||||
return mb_get_int32_generic(0, 1, 2, 3, pi32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_int32_abcd(pi32, i32)
|
||||
val_32_arr *pi32;
|
||||
int32_t i32;
|
||||
{
|
||||
return mb_set_int32_generic(0, 1, 2, 3, pi32, i32);
|
||||
}
|
||||
|
||||
uint32_t mb_get_uint32_abcd(pu32)
|
||||
val_32_arr *pu32;
|
||||
{
|
||||
return mb_get_uint32_generic(0, 1, 2, 3, pu32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_uint32_abcd(pu32, u32)
|
||||
val_32_arr *pu32;
|
||||
uint32_t u32;
|
||||
{
|
||||
return mb_set_uint32_generic(0, 1, 2, 3, pu32, u32);
|
||||
}
|
||||
|
||||
int32_t mb_get_int32_badc(pi32)
|
||||
val_32_arr *pi32;
|
||||
{
|
||||
return mb_get_int32_generic(1, 0, 3, 2, pi32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_int32_badc(pi32, i32)
|
||||
val_32_arr *pi32;
|
||||
int32_t i32;
|
||||
{
|
||||
return mb_set_int32_generic(1, 0, 3, 2, pi32, i32);
|
||||
}
|
||||
|
||||
uint32_t mb_get_uint32_badc(pu32)
|
||||
val_32_arr *pu32;
|
||||
{
|
||||
return mb_get_uint32_generic(1, 0, 3, 2, pu32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_uint32_badc(pu32, u32)
|
||||
val_32_arr *pu32;
|
||||
uint32_t u32;
|
||||
{
|
||||
return mb_set_uint32_generic(1, 0, 3, 2, pu32, u32);
|
||||
}
|
||||
|
||||
int32_t mb_get_int32_cdab(pi32)
|
||||
val_32_arr *pi32;
|
||||
{
|
||||
return mb_get_int32_generic(2, 3, 0, 1, pi32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_int32_cdab(pi32, i32)
|
||||
val_32_arr *pi32;
|
||||
int32_t i32;
|
||||
{
|
||||
return mb_set_int32_generic(2, 3, 0, 1, pi32, i32);
|
||||
}
|
||||
|
||||
uint32_t mb_get_uint32_cdab(pu32)
|
||||
val_32_arr *pu32;
|
||||
{
|
||||
return mb_get_uint32_generic(2, 3, 0, 1, pu32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_uint32_cdab(pu32, u32)
|
||||
val_32_arr *pu32;
|
||||
uint32_t u32;
|
||||
{
|
||||
return mb_set_uint32_generic(2, 3, 0, 1, pu32, u32);
|
||||
}
|
||||
|
||||
int32_t mb_get_int32_dcba(pi32)
|
||||
val_32_arr *pi32;
|
||||
{
|
||||
return mb_get_int32_generic(3, 2, 1, 0, pi32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_int32_dcba(pi32, i32)
|
||||
val_32_arr *pi32;
|
||||
int32_t i32;
|
||||
{
|
||||
return mb_set_int32_generic(3, 2, 1, 0, pi32, i32);
|
||||
}
|
||||
|
||||
uint32_t mb_get_uint32_dcba(pu32)
|
||||
val_32_arr *pu32;
|
||||
{
|
||||
return mb_get_uint32_generic(3, 2, 1, 0, pu32);
|
||||
}
|
||||
|
||||
uint32_t mb_set_uint32_dcba(pu32, u32)
|
||||
val_32_arr *pu32;
|
||||
uint32_t u32;
|
||||
{
|
||||
return mb_set_uint32_generic(3, 2, 1, 0, pu32, u32);
|
||||
}
|
||||
|
||||
float mb_get_float_abcd(pf)
|
||||
val_32_arr *pf;
|
||||
{
|
||||
return mb_get_float_generic(0, 1, 2, 3, pf);
|
||||
}
|
||||
|
||||
uint32_t mb_set_float_abcd(pf, f)
|
||||
val_32_arr *pf;
|
||||
float f;
|
||||
{
|
||||
return mb_set_float_generic(0, 1, 2, 3, pf, f);
|
||||
}
|
||||
|
||||
float mb_get_float_badc(pf)
|
||||
val_32_arr *pf;
|
||||
{
|
||||
return mb_get_float_generic(1, 0, 3, 2, pf);
|
||||
}
|
||||
|
||||
uint32_t mb_set_float_badc(pf, f)
|
||||
val_32_arr *pf;
|
||||
float f;
|
||||
{
|
||||
return mb_set_float_generic(1, 0, 3, 2, pf, f);
|
||||
}
|
||||
|
||||
float mb_get_float_cdab(pf)
|
||||
val_32_arr *pf;
|
||||
{
|
||||
return mb_get_float_generic(2, 3, 0, 1, pf);
|
||||
}
|
||||
|
||||
uint32_t mb_set_float_cdab(pf, f)
|
||||
val_32_arr *pf;
|
||||
float f;
|
||||
{
|
||||
return mb_set_float_generic(2, 3, 0, 1, pf, f);
|
||||
}
|
||||
|
||||
float mb_get_float_dcba(pf)
|
||||
val_32_arr *pf;
|
||||
{
|
||||
return mb_get_float_generic(3, 2, 1, 0, pf);
|
||||
}
|
||||
|
||||
uint32_t mb_set_float_dcba(pf, f)
|
||||
val_32_arr *pf;
|
||||
float f;
|
||||
{
|
||||
return mb_set_float_generic(3, 2, 1, 0, pf, f);
|
||||
}
|
||||
|
||||
double mb_get_double_abcdefgh(pd)
|
||||
val_64_arr *pd;
|
||||
{
|
||||
return mb_get_double_generic(0, 1, 2, 3, 4, 5, 6, 7, pd);
|
||||
}
|
||||
|
||||
uint64_t mb_set_double_abcdefgh(pd, d)
|
||||
val_64_arr *pd;
|
||||
double d;
|
||||
{
|
||||
return mb_set_double_generic(0, 1, 2, 3, 4, 5, 6, 7, pd, d);
|
||||
}
|
||||
|
||||
double mb_get_double_hgfedcba(pd)
|
||||
val_64_arr *pd;
|
||||
{
|
||||
return mb_get_double_generic(7, 6, 5, 4, 3, 2, 1, 0, pd);
|
||||
}
|
||||
|
||||
uint64_t mb_set_double_hgfedcba(pd, d)
|
||||
val_64_arr *pd;
|
||||
double d;
|
||||
{
|
||||
return mb_set_double_generic(7, 6, 5, 4, 3, 2, 1, 0, pd, d);
|
||||
}
|
||||
|
||||
double mb_get_double_ghefcdab(pd)
|
||||
val_64_arr *pd;
|
||||
{
|
||||
return mb_get_double_generic(6, 7, 4, 5, 2, 3, 0, 1, pd);
|
||||
}
|
||||
|
||||
uint64_t mb_set_double_ghefcdab(pd, d)
|
||||
val_64_arr *pd;
|
||||
double d;
|
||||
{
|
||||
return mb_set_double_generic(6, 7, 4, 5, 2, 3, 0, 1, pd, d);
|
||||
}
|
||||
|
||||
double mb_get_double_badcfehg(pd)
|
||||
val_64_arr *pd;
|
||||
{
|
||||
return mb_get_double_generic(1, 0, 3, 2, 5, 4, 7, 6, pd);
|
||||
}
|
||||
|
||||
uint64_t mb_set_double_badcfehg(pd, d)
|
||||
val_64_arr *pd;
|
||||
double d;
|
||||
{
|
||||
return mb_set_double_generic(1, 0, 3, 2, 5, 4, 7, 6, pd, d);
|
||||
}
|
||||
|
||||
int64_t mb_get_int64_abcdefgh(pi64)
|
||||
val_64_arr *pi64;
|
||||
{
|
||||
return mb_get_int64_generic(0, 1, 2, 3, 4, 5, 6, 7, pi64);
|
||||
}
|
||||
|
||||
uint64_t mb_set_int64_abcdefgh(pi, i)
|
||||
val_64_arr *pi;
|
||||
int64_t i;
|
||||
{
|
||||
return mb_set_int64_generic(0, 1, 2, 3, 4, 5, 6, 7, pi, i);
|
||||
}
|
||||
|
||||
int64_t mb_get_int64_hgfedcba(pi64)
|
||||
val_64_arr *pi64;
|
||||
{
|
||||
return mb_get_int64_generic(7, 6, 5, 4, 3, 2, 1, 0, pi64);
|
||||
}
|
||||
|
||||
uint64_t mb_set_int64_hgfedcba(pi, i)
|
||||
val_64_arr *pi;
|
||||
int64_t i;
|
||||
{
|
||||
return mb_set_int64_generic(7, 6, 5, 4, 3, 2, 1, 0, pi, i);
|
||||
}
|
||||
|
||||
int64_t mb_get_int64_ghefcdab(pi64)
|
||||
val_64_arr *pi64;
|
||||
{
|
||||
return mb_get_int64_generic(6, 7, 4, 5, 2, 3, 0, 1, pi64);
|
||||
}
|
||||
|
||||
uint64_t mb_set_int64_ghefcdab(pi, i)
|
||||
val_64_arr *pi;
|
||||
int64_t i;
|
||||
{
|
||||
return mb_set_int64_generic(6, 7, 4, 5, 2, 3, 0, 1, pi, i);
|
||||
}
|
||||
|
||||
int64_t mb_get_int64_badcfehg(pi64)
|
||||
val_64_arr *pi64;
|
||||
{
|
||||
return mb_get_int64_generic(1, 0, 3, 2, 5, 4, 7, 6, pi64);
|
||||
}
|
||||
|
||||
uint64_t mb_set_int64_badcfehg(pi, i)
|
||||
val_64_arr *pi;
|
||||
int64_t i;
|
||||
{
|
||||
return mb_set_int64_generic(1, 0, 3, 2, 5, 4, 7, 6, pi, i);
|
||||
}
|
||||
|
||||
uint64_t mb_get_uint64_abcdefgh(pui)
|
||||
val_64_arr *pui;
|
||||
{
|
||||
return mb_get_uint64_generic(0, 1, 2, 3, 4, 5, 6, 7, pui);
|
||||
}
|
||||
|
||||
uint64_t mb_set_uint64_abcdefgh(pui, ui)
|
||||
val_64_arr *pui;
|
||||
uint64_t ui;
|
||||
{
|
||||
return mb_set_uint64_generic(0, 1, 2, 3, 4, 5, 6, 7, pui, ui);
|
||||
}
|
||||
|
||||
uint64_t mb_get_uint64_hgfedcba(pui)
|
||||
val_64_arr *pui;
|
||||
{
|
||||
return mb_get_uint64_generic(7, 6, 5, 4, 3, 2, 1, 0, pui);
|
||||
}
|
||||
|
||||
uint64_t mb_set_uint64_hgfedcba(pui, ui)
|
||||
val_64_arr *pui;
|
||||
uint64_t ui;
|
||||
{
|
||||
return mb_set_uint64_generic(7, 6, 5, 4, 3, 2, 1, 0, pui, ui);
|
||||
}
|
||||
|
||||
uint64_t mb_get_uint64_ghefcdab(pui)
|
||||
val_64_arr *pui;
|
||||
{
|
||||
return mb_get_uint64_generic(6, 7, 4, 5, 2, 3, 0, 1, pui);
|
||||
}
|
||||
|
||||
uint64_t mb_set_uint64_ghefcdab(pui, ui)
|
||||
val_64_arr *pui;
|
||||
uint64_t ui;
|
||||
{
|
||||
return mb_set_uint64_generic(6, 7, 4, 5, 2, 3, 0, 1, pui, ui);
|
||||
}
|
||||
|
||||
uint64_t mb_get_uint64_badcfehg(pui)
|
||||
val_64_arr *pui;
|
||||
{
|
||||
return mb_get_int64_generic(1, 0, 3, 2, 5, 4, 7, 6, pui);
|
||||
}
|
||||
|
||||
uint64_t mb_set_uint64_badcfehg(pui, ui)
|
||||
val_64_arr *pui;
|
||||
uint64_t ui;
|
||||
{
|
||||
return mb_set_uint64_generic(1, 0, 3, 2, 5, 4, 7, 6, pui, ui);
|
||||
}
|
@ -375,57 +375,85 @@ static esp_err_t mbc_serial_master_set_request(char* name, mb_param_mode_t mode,
|
||||
return error;
|
||||
}
|
||||
|
||||
// Get parameter data for corresponding characteristic
|
||||
static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
|
||||
uint8_t* value_ptr, uint8_t *type)
|
||||
static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name, uint8_t* value, uint8_t *type)
|
||||
{
|
||||
MB_MASTER_CHECK((name != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
|
||||
MB_MASTER_CHECK((type != NULL),
|
||||
ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
|
||||
MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
|
||||
MB_MASTER_CHECK((type != NULL), ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
|
||||
MB_MASTER_CHECK((value != NULL), ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
|
||||
esp_err_t error = ESP_ERR_INVALID_RESPONSE;
|
||||
mb_param_request_t request ;
|
||||
mb_parameter_descriptor_t reg_info = { 0 };
|
||||
uint8_t* pdata = NULL;
|
||||
|
||||
error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, ®_info);
|
||||
if ((error == ESP_OK) && (cid == reg_info.cid)) {
|
||||
// Send request to read characteristic data
|
||||
error = mbc_serial_master_send_request(&request, value_ptr);
|
||||
MB_MASTER_CHECK(((reg_info.mb_size << 1) >= reg_info.param_size),
|
||||
MB_EILLSTATE,
|
||||
"Incorrect characteristic data.");
|
||||
// alloc buffer to store parameter data
|
||||
pdata = calloc(1, (reg_info.mb_size << 1));
|
||||
if (!pdata) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
error = mbc_serial_master_send_request(&request, pdata);
|
||||
if (error == ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
// If data pointer is NULL then we don't need to set value (it is still in the cache of cid)
|
||||
if (value != NULL) {
|
||||
error = mbc_master_set_param_data((void*)value, (void*)pdata,
|
||||
reg_info.param_type, reg_info.param_size);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||
error = ESP_ERR_INVALID_STATE;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
}
|
||||
free(pdata);
|
||||
// Set the type of parameter found in the table
|
||||
*type = reg_info.param_type;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
|
||||
__FUNCTION__, (unsigned)reg_info.cid);
|
||||
ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.", __FUNCTION__, reg_info.cid);
|
||||
error = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// Set parameter value for characteristic selected by name and cid
|
||||
static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
|
||||
uint8_t* value_ptr, uint8_t *type)
|
||||
static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uint8_t *type)
|
||||
{
|
||||
MB_MASTER_CHECK((name != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
|
||||
MB_MASTER_CHECK((value_ptr != NULL),
|
||||
ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
|
||||
MB_MASTER_CHECK((type != NULL),
|
||||
ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
|
||||
MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
|
||||
MB_MASTER_CHECK((value != NULL), ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
|
||||
MB_MASTER_CHECK((type != NULL), ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
|
||||
|
||||
esp_err_t error = ESP_ERR_INVALID_RESPONSE;
|
||||
mb_param_request_t request ;
|
||||
mb_parameter_descriptor_t reg_info = { 0 };
|
||||
uint8_t* pdata = NULL;
|
||||
|
||||
error = mbc_serial_master_set_request(name, MB_PARAM_WRITE, &request, ®_info);
|
||||
if ((error == ESP_OK) && (cid == reg_info.cid)) {
|
||||
MB_MASTER_CHECK(((reg_info.mb_size << 1) >= reg_info.param_size),
|
||||
MB_EILLSTATE,
|
||||
"Incorrect characteristic data.");
|
||||
pdata = calloc(1, (reg_info.mb_size << 1)); // alloc parameter buffer
|
||||
if (!pdata) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
// Transfer value of characteristic into parameter buffer
|
||||
error = mbc_master_set_param_data((void*)pdata, (void*)value,
|
||||
reg_info.param_type, reg_info.param_size);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||
free(pdata);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
// Send request to write characteristic data
|
||||
error = mbc_serial_master_send_request(&request, value_ptr);
|
||||
error = mbc_serial_master_send_request(&request, pdata);
|
||||
if (error == ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
@ -435,6 +463,7 @@ static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
|
||||
}
|
||||
// Set the type of parameter found in the table
|
||||
*type = reg_info.param_type;
|
||||
free(pdata);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
|
||||
__FUNCTION__, (unsigned)reg_info.cid);
|
||||
|
@ -404,39 +404,6 @@ static uint8_t mbc_tcp_master_get_command(mb_param_type_t param_type, mb_param_m
|
||||
return command;
|
||||
}
|
||||
|
||||
// Helper function to set parameter buffer according to its type
|
||||
static esp_err_t mbc_tcp_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
MB_MASTER_CHECK((dest != NULL), ESP_ERR_INVALID_ARG, "incorrect parameter pointer.");
|
||||
MB_MASTER_CHECK((src != NULL), ESP_ERR_INVALID_ARG, "incorrect parameter pointer.");
|
||||
// Transfer parameter data into value of characteristic
|
||||
switch(param_type)
|
||||
{
|
||||
case PARAM_TYPE_U8:
|
||||
*((uint8_t*)dest) = *((uint8_t*)src);
|
||||
break;
|
||||
case PARAM_TYPE_U16:
|
||||
*((uint16_t*)dest) = *((uint16_t*)src);
|
||||
break;
|
||||
case PARAM_TYPE_U32:
|
||||
*((uint32_t*)dest) = *((uint32_t*)src);
|
||||
break;
|
||||
case PARAM_TYPE_FLOAT:
|
||||
*((float*)dest) = *(float*)src;
|
||||
break;
|
||||
case PARAM_TYPE_ASCII:
|
||||
memcpy((void*)dest, (void*)src, (size_t)param_size);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u).",
|
||||
__FUNCTION__, (unsigned)param_type);
|
||||
err = ESP_ERR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// Helper to search parameter by name in the parameter description table and fills Modbus request fields accordingly
|
||||
static esp_err_t mbc_tcp_master_set_request(char* name, mb_param_mode_t mode, mb_param_request_t* request,
|
||||
mb_parameter_descriptor_t* reg_data)
|
||||
@ -498,7 +465,7 @@ static esp_err_t mbc_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t*
|
||||
if (error == ESP_OK) {
|
||||
// If data pointer is NULL then we don't need to set value (it is still in the cache of cid)
|
||||
if (value != NULL) {
|
||||
error = mbc_tcp_master_set_param_data((void*)value, (void*)pdata,
|
||||
error = mbc_master_set_param_data((void*)value, (void*)pdata,
|
||||
reg_info.param_type, reg_info.param_size);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||
@ -541,7 +508,7 @@ static esp_err_t mbc_tcp_master_set_parameter(uint16_t cid, char* name, uint8_t*
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
// Transfer value of characteristic into parameter buffer
|
||||
error = mbc_tcp_master_set_param_data((void*)pdata, (void*)value,
|
||||
error = mbc_master_set_param_data((void*)pdata, (void*)value,
|
||||
reg_info.param_type, reg_info.param_size);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||
|
@ -23,6 +23,9 @@ markers =
|
||||
esp32s3: support esp32s3 target
|
||||
esp32c3: support esp32c3 target
|
||||
esp32c2: support esp32c2 target
|
||||
esp32c6: support esp32c6 target
|
||||
esp32h2: support esp32h2 target
|
||||
esp32p4: support esp32p4 target
|
||||
|
||||
# env markers
|
||||
generic: tests should be run on generic runners
|
||||
@ -31,6 +34,8 @@ markers =
|
||||
multi_dut_generic: tests should be run on generic runners, at least have two duts connected.
|
||||
multi_dut_modbus_tcp: Modbus TCP runners with two duts connected
|
||||
multi_dut_modbus_rs485: Modbus RTU/ASCII runners with two duts connected
|
||||
multi_dut_modbus_serial: Modbus SERIAL runner with two duts (master, slave - additional)
|
||||
multi_dut_modbus_generic: Modbus generic runner
|
||||
|
||||
# log related
|
||||
log_cli = True
|
||||
|
@ -12,6 +12,11 @@ tcp/mb_tcp_slave:
|
||||
disable:
|
||||
- if: CONFIG_NAME == "wifi" and SOC_WIFI_SUPPORTED != 1
|
||||
|
||||
test_apps/ext_types:
|
||||
disable:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: this is workaround to decrease of artifacts size
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ class ModbusTestDut(IdfDut):
|
||||
TEST_IP_PROMPT = r'Waiting IP([0-9]{1,2}) from stdin:\r\r\n'
|
||||
TEST_IP_SET_CONFIRM = r'.*IP\([0-9]+\) = \[([0-9a-zA-Z\.\:]+)\] set from stdin.*'
|
||||
TEST_IP_ADDRESS_REGEXP = r'.*example_[a-z]+: .* IPv4 [a-z]+:.* ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*'
|
||||
TEST_APP_NAME = r'I \([0-9]+\) cpu_start: Project name: ([_a-z]*)'
|
||||
TEST_APP_NAME = r'.*Project name: ([_a-z]*)'
|
||||
|
||||
TEST_EXPECT_STR_TIMEOUT = 120
|
||||
TEST_ACK_TIMEOUT = 60
|
||||
|
8
test/generic/ext_types/CMakeLists.txt
Normal file
8
test/generic/ext_types/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
#This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mb_endianness_utils)
|
3
test/generic/ext_types/README.md
Normal file
3
test/generic/ext_types/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
7
test/generic/ext_types/main/CMakeLists.txt
Normal file
7
test/generic/ext_types/main/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
set(srcs "test_mb_endianness_utils.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES esp-modbus test_utils unity)
|
||||
|
||||
|
6
test/generic/ext_types/main/idf_component.yml
Normal file
6
test/generic/ext_types/main/idf_component.yml
Normal file
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
idf: ">=4.3"
|
||||
espressif/esp-modbus:
|
||||
version: "^1.0"
|
||||
override_path: "../../../../"
|
||||
|
149
test/generic/ext_types/main/test_mb_endianness_utils.c
Normal file
149
test/generic/ext_types/main/test_mb_endianness_utils.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "mb_endianness_utils.h"
|
||||
|
||||
#define TAG "MB_ENDIANNESS_TEST"
|
||||
|
||||
// The below is the data used for endianness conversion test
|
||||
|
||||
const uint16_t TEST_INT8_A = 0x00F6;
|
||||
const uint16_t TEST_INT8_B = 0xF600;
|
||||
|
||||
const uint16_t TEST_UINT8_A = 0x0037;
|
||||
const uint16_t TEST_UINT8_B = 0x3700;
|
||||
|
||||
const uint16_t TEST_UINT16_AB = 0x3039;
|
||||
const uint16_t TEST_UINT16_BA = 0x3930;
|
||||
const uint16_t TEST_INT16_AB = 0x3039;
|
||||
const uint16_t TEST_INT16_BA = 0x3930;
|
||||
|
||||
const uint32_t TEST_FLOAT_ABCD = 0x4640e400;
|
||||
const uint32_t TEST_FLOAT_DCBA = 0x00e44046;
|
||||
const uint32_t TEST_FLOAT_BADC = 0x404600e4;
|
||||
const uint32_t TEST_FLOAT_CDAB = 0xe4004640;
|
||||
|
||||
const uint32_t TEST_UINT32_ABCD = 0x11223344;
|
||||
const uint32_t TEST_UINT32_DCBA = 0x44332211;
|
||||
const uint32_t TEST_UINT32_BADC = 0x22114433;
|
||||
const uint32_t TEST_UINT32_CDAB = 0x33441122;
|
||||
|
||||
const uint64_t TEST_DOUBLE_ABCDEFGH = 0x40c81c8000000000;
|
||||
const uint64_t TEST_DOUBLE_HGFEDCBA = 0x00000000801cc840;
|
||||
const uint64_t TEST_DOUBLE_GHEFCDAB = 0x000000001c8040c8;
|
||||
const uint64_t TEST_DOUBLE_BADCFEHG = 0xc840801c00000000;
|
||||
|
||||
const uint64_t TEST_INT64_ABCDEFGH = 0xffffffffffffcfc7;
|
||||
const uint64_t TEST_INT64_HGFEDCBA = 0xc7cfffffffffffff;
|
||||
const uint64_t TEST_INT64_GHEFCDAB = 0xcfc7ffffffffffff;
|
||||
const uint64_t TEST_INT64_BADCFEHG = 0xffffffffffffc7cf;
|
||||
|
||||
const uint64_t TEST_UINT64_ABCDEFGH = 0x1122334455667788;
|
||||
const uint64_t TEST_UINT64_HGFEDCBA = 0x8877665544332211;
|
||||
const uint64_t TEST_UINT64_GHEFCDAB = 0x7788556633441122;
|
||||
const uint64_t TEST_UINT64_BADCFEHG = 0x2211443366558877;
|
||||
|
||||
TEST_CASE("Test endianness conversion for all extended Modbus types.", "[MB_ENDIANNESS]")
|
||||
{
|
||||
val_16_arr arr_16 = {0};
|
||||
val_32_arr arr_32 = {0};
|
||||
val_64_arr arr_64 = {0};
|
||||
|
||||
TEST_ASSERT(mb_set_uint8_a(&arr_16, (uint8_t)55) == TEST_UINT8_A);
|
||||
TEST_ASSERT(mb_get_uint8_a(&arr_16) == (uint8_t)55);
|
||||
TEST_ASSERT(mb_set_int8_a(&arr_16, (int8_t)-10) == TEST_INT8_A);
|
||||
TEST_ASSERT(mb_get_int8_a(&arr_16) == (int8_t)-10);
|
||||
|
||||
TEST_ASSERT(mb_set_uint8_b(&arr_16, (uint8_t)55) == TEST_UINT8_B);
|
||||
TEST_ASSERT(mb_get_uint8_b(&arr_16) == (uint8_t)55);
|
||||
TEST_ASSERT(mb_set_int8_b(&arr_16, (int8_t)-10) == TEST_INT8_B);
|
||||
TEST_ASSERT(mb_get_int8_b(&arr_16) == (int8_t)-10);
|
||||
|
||||
TEST_ASSERT(mb_set_uint16_ab(&arr_16, (uint16_t)12345) == TEST_UINT16_AB);
|
||||
TEST_ASSERT(mb_get_uint16_ab(&arr_16) == (uint16_t)12345);
|
||||
TEST_ASSERT(mb_set_int16_ab(&arr_16, (int16_t)12345) == TEST_INT16_AB);
|
||||
TEST_ASSERT(mb_get_int16_ab(&arr_16) == (int16_t)12345);
|
||||
|
||||
TEST_ASSERT(mb_set_uint16_ba(&arr_16, (uint16_t)12345) == TEST_UINT16_BA);
|
||||
TEST_ASSERT(mb_get_uint16_ba(&arr_16) == (uint16_t)12345);
|
||||
TEST_ASSERT(mb_set_int16_ba(&arr_16, (int16_t)12345) == TEST_INT16_BA);
|
||||
TEST_ASSERT(mb_get_int16_ba(&arr_16) == (int16_t)12345);
|
||||
|
||||
TEST_ASSERT(mb_set_uint16_ab(&arr_16, (uint16_t)12345) == TEST_UINT16_AB);
|
||||
TEST_ASSERT(mb_get_uint16_ab(&arr_16) == (uint16_t)12345);
|
||||
TEST_ASSERT(mb_set_int16_ab(&arr_16, (int16_t)12345) == TEST_INT16_AB);
|
||||
TEST_ASSERT(mb_get_int16_ab(&arr_16) == (int16_t)12345);
|
||||
|
||||
TEST_ASSERT(mb_set_float_abcd(&arr_32, (float)12345.0) == TEST_FLOAT_ABCD);
|
||||
TEST_ASSERT(mb_get_float_abcd(&arr_32) == (float)12345.0);
|
||||
|
||||
TEST_ASSERT(mb_set_float_badc(&arr_32, (float)12345.0) == TEST_FLOAT_BADC);
|
||||
TEST_ASSERT(mb_get_float_badc(&arr_32) == (float)12345.0);
|
||||
|
||||
TEST_ASSERT(mb_set_float_cdab(&arr_32, (float)12345.0) == TEST_FLOAT_CDAB);
|
||||
TEST_ASSERT(mb_get_float_cdab(&arr_32) == (float)12345.0);
|
||||
|
||||
TEST_ASSERT(mb_set_float_dcba(&arr_32, (float)12345.0) == TEST_FLOAT_DCBA);
|
||||
TEST_ASSERT(mb_get_float_dcba(&arr_32) == (float)12345.0);
|
||||
|
||||
TEST_ASSERT(mb_set_uint32_abcd(&arr_32, (uint32_t)0x11223344) == TEST_UINT32_ABCD);
|
||||
TEST_ASSERT(mb_get_uint32_abcd(&arr_32) == (uint32_t)0x11223344);
|
||||
TEST_ASSERT(mb_set_int32_abcd(&arr_32, (int32_t)0x11223344) == TEST_UINT32_ABCD);
|
||||
TEST_ASSERT(mb_get_int32_abcd(&arr_32) == (int32_t)0x11223344);
|
||||
|
||||
TEST_ASSERT(mb_set_uint32_badc(&arr_32, (uint32_t)0x11223344) == TEST_UINT32_BADC);
|
||||
TEST_ASSERT(mb_get_uint32_badc(&arr_32) == (uint32_t)0x11223344);
|
||||
TEST_ASSERT(mb_set_int32_badc(&arr_32, (int32_t)0x11223344) == TEST_UINT32_BADC);
|
||||
TEST_ASSERT(mb_get_int32_badc(&arr_32) == (int32_t)0x11223344);
|
||||
|
||||
TEST_ASSERT(mb_set_uint32_cdab(&arr_32, (uint32_t)0x11223344) == TEST_UINT32_CDAB);
|
||||
TEST_ASSERT(mb_get_uint32_cdab(&arr_32) == (uint32_t)0x11223344);
|
||||
TEST_ASSERT(mb_set_int32_cdab(&arr_32, (int32_t)0x11223344) == TEST_UINT32_CDAB);
|
||||
TEST_ASSERT(mb_get_int32_cdab(&arr_32) == (int32_t)0x11223344);
|
||||
|
||||
TEST_ASSERT(mb_set_uint32_dcba(&arr_32, (uint32_t)0x11223344) == TEST_UINT32_DCBA);
|
||||
TEST_ASSERT(mb_get_uint32_dcba(&arr_32) == (uint32_t)0x11223344);
|
||||
TEST_ASSERT(mb_set_int32_dcba(&arr_32, (int32_t)0x11223344) == TEST_UINT32_DCBA);
|
||||
TEST_ASSERT(mb_get_int32_dcba(&arr_32) == (int32_t)0x11223344);
|
||||
|
||||
TEST_ASSERT(mb_set_double_abcdefgh(&arr_64, (double)12345.0) == TEST_DOUBLE_ABCDEFGH);
|
||||
TEST_ASSERT(mb_get_double_abcdefgh(&arr_64) == (double)12345.0);
|
||||
TEST_ASSERT(mb_set_uint64_abcdefgh(&arr_64, (uint64_t)0x1122334455667788) == TEST_UINT64_ABCDEFGH);
|
||||
TEST_ASSERT(mb_get_uint64_abcdefgh(&arr_64) == (uint64_t)0x1122334455667788);
|
||||
TEST_ASSERT(mb_set_int64_abcdefgh(&arr_64, (int64_t)-12345) == TEST_INT64_ABCDEFGH);
|
||||
TEST_ASSERT(mb_get_int64_abcdefgh(&arr_64) == (int64_t)-12345);
|
||||
|
||||
TEST_ASSERT(mb_set_double_hgfedcba(&arr_64, (double)12345.0) == TEST_DOUBLE_HGFEDCBA);
|
||||
TEST_ASSERT(mb_get_double_hgfedcba(&arr_64) == (double)12345.0);
|
||||
TEST_ASSERT(mb_set_uint64_hgfedcba(&arr_64, (uint64_t)0x1122334455667788) == TEST_UINT64_HGFEDCBA);
|
||||
TEST_ASSERT(mb_get_uint64_hgfedcba(&arr_64) == (uint64_t)0x1122334455667788);
|
||||
TEST_ASSERT(mb_set_int64_hgfedcba(&arr_64, (int64_t)-12345) == TEST_INT64_HGFEDCBA);
|
||||
TEST_ASSERT(mb_get_int64_hgfedcba(&arr_64) == (int64_t)-12345);
|
||||
|
||||
TEST_ASSERT(mb_set_double_ghefcdab(&arr_64, (double)12345.0) == TEST_DOUBLE_GHEFCDAB);
|
||||
TEST_ASSERT(mb_get_double_ghefcdab(&arr_64) == (double)12345.0);
|
||||
TEST_ASSERT(mb_set_uint64_ghefcdab(&arr_64, (uint64_t)0x1122334455667788) == TEST_UINT64_GHEFCDAB);
|
||||
TEST_ASSERT(mb_get_uint64_ghefcdab(&arr_64) == (uint64_t)0x1122334455667788);
|
||||
TEST_ASSERT(mb_set_int64_ghefcdab(&arr_64, (int64_t)-12345) == TEST_INT64_GHEFCDAB);
|
||||
TEST_ASSERT(mb_get_int64_ghefcdab(&arr_64) == (int64_t)-12345);
|
||||
|
||||
TEST_ASSERT(mb_set_double_badcfehg(&arr_64, (double)12345.0) == TEST_DOUBLE_BADCFEHG);
|
||||
TEST_ASSERT(mb_get_double_badcfehg(&arr_64) == (double)12345.0);
|
||||
TEST_ASSERT(mb_set_uint64_badcfehg(&arr_64, (uint64_t)0x1122334455667788) == TEST_UINT64_BADCFEHG);
|
||||
TEST_ASSERT(mb_get_uint64_badcfehg(&arr_64) == (uint64_t)0x1122334455667788);
|
||||
TEST_ASSERT(mb_set_int64_badcfehg(&arr_64, (int64_t)-12345) == TEST_INT64_BADCFEHG);
|
||||
TEST_ASSERT(mb_get_int64_badcfehg(&arr_64) == (int64_t)-12345);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
11
test/generic/ext_types/pytest_mb_endianness_utils.py
Normal file
11
test/generic/ext_types/pytest_mb_endianness_utils.py
Normal file
@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.generic
|
||||
def test_mb_endianness_utils(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
2
test/generic/ext_types/sdkconfig.defaults
Normal file
2
test/generic/ext_types/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
# General options for test
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
@ -13,6 +13,8 @@
|
||||
#ifndef _DEVICE_PARAMS
|
||||
#define _DEVICE_PARAMS
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// This file defines structure of modbus parameters which reflect correspond modbus address space
|
||||
// for each modbus register type (coils, discreet inputs, holding registers, input registers)
|
||||
#pragma pack(push, 1)
|
||||
@ -59,6 +61,25 @@ typedef struct
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
uint16_t holding_u8_a[2];
|
||||
uint16_t holding_u8_b[2];
|
||||
uint16_t holding_u16_ab[2];
|
||||
uint16_t holding_u16_ba[2];
|
||||
uint32_t holding_uint32_abcd[2];
|
||||
uint32_t holding_uint32_cdab[2];
|
||||
uint32_t holding_uint32_badc[2];
|
||||
uint32_t holding_uint32_dcba[2];
|
||||
float holding_float_abcd[2];
|
||||
float holding_float_cdab[2];
|
||||
float holding_float_badc[2];
|
||||
float holding_float_dcba[2];
|
||||
double holding_double_abcdefgh[2];
|
||||
double holding_double_hgfedcba[2];
|
||||
double holding_double_ghefcdab[2];
|
||||
double holding_double_badcfehg[2];
|
||||
uint32_t holding_area2_end;
|
||||
#endif
|
||||
float holding_data0;
|
||||
float holding_data1;
|
||||
float holding_data2;
|
||||
@ -68,6 +89,7 @@ typedef struct
|
||||
float holding_data5;
|
||||
float holding_data6;
|
||||
float holding_data7;
|
||||
uint32_t holding_area1_end;
|
||||
} holding_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -37,10 +37,22 @@
|
||||
// Discrete offset macro
|
||||
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
|
||||
|
||||
#define STR(fieldname) ((const char*)( fieldname ))
|
||||
#define STR(fieldname) ((const char *)( fieldname ))
|
||||
#define TEST_HOLD_REG_START(field) (HOLD_OFFSET(field) >> 1)
|
||||
#define TEST_HOLD_REG_SIZE(field) (sizeof(((holding_reg_params_t *)0)->field) >> 1)
|
||||
|
||||
#define TEST_INPUT_REG_START(field) (INPUT_OFFSET(field) >> 1)
|
||||
#define TEST_INPUT_REG_SIZE(field) (sizeof(((input_reg_params_t *)0)->field) >> 1)
|
||||
|
||||
#define TEST_VALUE 12345 // default test value
|
||||
#define TEST_ASCII_BIN 0xAAAAAAAA
|
||||
|
||||
// Options can be used as bit masks or parameter limits
|
||||
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
|
||||
|
||||
#define EACH_ITEM(array, length) \
|
||||
(typeof(*(array)) *pitem = (array); (pitem < &((array)[length])); pitem++)
|
||||
|
||||
static const char *TAG = "MASTER_TEST";
|
||||
|
||||
// Enumeration of modbus device addresses accessed by master device
|
||||
@ -60,6 +72,24 @@ enum {
|
||||
CID_RELAY_P1,
|
||||
CID_RELAY_P2,
|
||||
CID_DISCR_P1,
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
CID_HOLD_U8_A,
|
||||
CID_HOLD_U8_B,
|
||||
CID_HOLD_U16_AB,
|
||||
CID_HOLD_U16_BA,
|
||||
CID_HOLD_UINT32_ABCD,
|
||||
CID_HOLD_UINT32_CDAB,
|
||||
CID_HOLD_UINT32_BADC,
|
||||
CID_HOLD_UINT32_DCBA,
|
||||
CID_HOLD_FLOAT_ABCD,
|
||||
CID_HOLD_FLOAT_CDAB,
|
||||
CID_HOLD_FLOAT_BADC,
|
||||
CID_HOLD_FLOAT_DCBA,
|
||||
CID_HOLD_DOUBLE_ABCDEFGH,
|
||||
CID_HOLD_DOUBLE_HGFEDCBA,
|
||||
CID_HOLD_DOUBLE_GHEFCDAB,
|
||||
CID_HOLD_DOUBLE_BADCFEHG,
|
||||
#endif
|
||||
CID_COUNT
|
||||
};
|
||||
|
||||
@ -74,26 +104,109 @@ enum {
|
||||
// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc).
|
||||
const mb_parameter_descriptor_t device_parameters[] = {
|
||||
// { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
|
||||
{ CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
|
||||
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
|
||||
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 2,
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 4, 2,
|
||||
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2,
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 10, 58,
|
||||
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 116, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data0), TEST_INPUT_REG_SIZE(input_data0),
|
||||
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data0), TEST_HOLD_REG_SIZE(holding_data0),
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data1), TEST_INPUT_REG_SIZE(input_data1),
|
||||
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( -40, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data1), TEST_HOLD_REG_SIZE(holding_data1),
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data2), TEST_INPUT_REG_SIZE(input_data2),
|
||||
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( -40, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data2), TEST_HOLD_REG_SIZE(holding_data2),
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(test_regs), 58,
|
||||
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 116,
|
||||
OPTS( 0, 100, TEST_ASCII_BIN ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 2, 6,
|
||||
COIL_OFFSET(coils_port0), PARAM_TYPE_U8, 1, OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
COIL_OFFSET(coils_port0), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_RELAY_P2, STR("RelayP2"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 10, 6,
|
||||
COIL_OFFSET(coils_port1), PARAM_TYPE_U8, 1, OPTS( 0x55, 0x2A, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
COIL_OFFSET(coils_port1), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0x55, 0x2A, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_DISCR_P1, STR("DiscreteInpP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_DISCRETE, 2, 7,
|
||||
DISCR_OFFSET(discrete_input_port1), PARAM_TYPE_U8, 1, OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER }
|
||||
DISCR_OFFSET(discrete_input_port1), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
{ CID_HOLD_U8_A, STR("U8_A"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u8_a), TEST_HOLD_REG_SIZE(holding_u8_a),
|
||||
HOLD_OFFSET(holding_u8_a), PARAM_TYPE_U8_A, (TEST_HOLD_REG_SIZE(holding_u8_a) << 1),
|
||||
OPTS( CHAR_MIN, 0x0055, 0x0055 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_U8_B, STR("U8_B"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u8_b), TEST_HOLD_REG_SIZE(holding_u8_b),
|
||||
HOLD_OFFSET(holding_u8_b), PARAM_TYPE_U8_B, (TEST_HOLD_REG_SIZE(holding_u8_b) << 1),
|
||||
OPTS( 0, 0x5500, 0x5500 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_U16_AB, STR("U16_AB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u16_ab), TEST_HOLD_REG_SIZE(holding_u16_ab),
|
||||
HOLD_OFFSET(holding_u16_ab), PARAM_TYPE_U16_AB, (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_U16_BA, STR("U16_BA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u16_ba), TEST_HOLD_REG_SIZE(holding_u16_ba),
|
||||
HOLD_OFFSET(holding_u16_ba), PARAM_TYPE_U16_BA, (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_ABCD, STR("UINT32_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_abcd), TEST_HOLD_REG_SIZE(holding_uint32_abcd),
|
||||
HOLD_OFFSET(holding_uint32_abcd), PARAM_TYPE_U32_ABCD, (TEST_HOLD_REG_SIZE(holding_uint32_abcd) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_CDAB, STR("UINT32_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_cdab), TEST_HOLD_REG_SIZE(holding_uint32_cdab),
|
||||
HOLD_OFFSET(holding_uint32_cdab), PARAM_TYPE_U32_CDAB, (TEST_HOLD_REG_SIZE(holding_uint32_cdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_BADC, STR("UINT32_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_badc), TEST_HOLD_REG_SIZE(holding_uint32_badc),
|
||||
HOLD_OFFSET(holding_uint32_badc), PARAM_TYPE_U32_BADC, (TEST_HOLD_REG_SIZE(holding_uint32_badc) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_DCBA, STR("UINT32_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_dcba), TEST_HOLD_REG_SIZE(holding_uint32_dcba),
|
||||
HOLD_OFFSET(holding_uint32_dcba), PARAM_TYPE_U32_DCBA, (TEST_HOLD_REG_SIZE(holding_uint32_dcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_ABCD, STR("FLOAT_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_abcd), TEST_HOLD_REG_SIZE(holding_float_abcd),
|
||||
HOLD_OFFSET(holding_float_abcd), PARAM_TYPE_FLOAT_ABCD, (TEST_HOLD_REG_SIZE(holding_float_abcd) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_CDAB, STR("FLOAT_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_cdab), TEST_HOLD_REG_SIZE(holding_float_cdab),
|
||||
HOLD_OFFSET(holding_float_cdab), PARAM_TYPE_FLOAT_CDAB, (TEST_HOLD_REG_SIZE(holding_float_cdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_BADC, STR("FLOAT_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_badc), TEST_HOLD_REG_SIZE(holding_float_badc),
|
||||
HOLD_OFFSET(holding_float_badc), PARAM_TYPE_FLOAT_BADC, (TEST_HOLD_REG_SIZE(holding_float_badc) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_DCBA, STR("FLOAT_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_dcba), TEST_HOLD_REG_SIZE(holding_float_dcba),
|
||||
HOLD_OFFSET(holding_float_dcba), PARAM_TYPE_FLOAT_DCBA, (TEST_HOLD_REG_SIZE(holding_float_dcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_ABCDEFGH, STR("DOUBLE_ABCDEFGH"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_abcdefgh), TEST_HOLD_REG_SIZE(holding_double_abcdefgh),
|
||||
HOLD_OFFSET(holding_double_abcdefgh), PARAM_TYPE_DOUBLE_ABCDEFGH, (TEST_HOLD_REG_SIZE(holding_double_abcdefgh) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_HGFEDCBA, STR("DOUBLE_HGFEDCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_hgfedcba), TEST_HOLD_REG_SIZE(holding_double_hgfedcba),
|
||||
HOLD_OFFSET(holding_double_hgfedcba), PARAM_TYPE_DOUBLE_HGFEDCBA, (TEST_HOLD_REG_SIZE(holding_double_hgfedcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_GHEFCDAB, STR("DOUBLE_GHEFCDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_ghefcdab), TEST_HOLD_REG_SIZE(holding_double_ghefcdab),
|
||||
HOLD_OFFSET(holding_double_ghefcdab), PARAM_TYPE_DOUBLE_GHEFCDAB, (TEST_HOLD_REG_SIZE(holding_double_ghefcdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_BADCFEHG, STR("DOUBLE_BADCFEHG"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_badcfehg), TEST_HOLD_REG_SIZE(holding_double_badcfehg),
|
||||
HOLD_OFFSET(holding_double_badcfehg), PARAM_TYPE_DOUBLE_BADCFEHG, (TEST_HOLD_REG_SIZE(holding_double_badcfehg) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER }
|
||||
#endif
|
||||
};
|
||||
|
||||
// Calculate number of parameters in the table
|
||||
@ -108,16 +221,16 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
|
||||
switch(param_descriptor->mb_param_type)
|
||||
{
|
||||
case MB_PARAM_HOLDING:
|
||||
instance_ptr = ((void*)&holding_reg_params + param_descriptor->param_offset - 1);
|
||||
instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_INPUT:
|
||||
instance_ptr = ((void*)&input_reg_params + param_descriptor->param_offset - 1);
|
||||
instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_COIL:
|
||||
instance_ptr = ((void*)&coil_reg_params + param_descriptor->param_offset - 1);
|
||||
instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_DISCRETE:
|
||||
instance_ptr = ((void*)&discrete_reg_params + param_descriptor->param_offset - 1);
|
||||
instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
default:
|
||||
instance_ptr = NULL;
|
||||
@ -130,11 +243,62 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
|
||||
return instance_ptr;
|
||||
}
|
||||
|
||||
#define TEST_VERIFY_VALUES(pdescr, pinst) (__extension__( \
|
||||
{ \
|
||||
assert(pinst); \
|
||||
assert(pdescr); \
|
||||
uint8_t type = 0; \
|
||||
esp_err_t err = ESP_FAIL; \
|
||||
err = mbc_master_get_parameter(pdescr->cid, (char *)pdescr->param_key, \
|
||||
(uint8_t *)pinst, &type); \
|
||||
if (err == ESP_OK) { \
|
||||
bool is_correct = true; \
|
||||
if (pdescr->param_opts.opt3) { \
|
||||
for EACH_ITEM(pinst, pdescr->param_size / sizeof(*pitem)) { \
|
||||
if (*pitem != (typeof(*(pinst)))pdescr->param_opts.opt3) { \
|
||||
*pitem = (typeof(*(pinst)))pdescr->param_opts.opt3; \
|
||||
ESP_LOGD(TAG, "Characteristic #%d (%s), initialize to 0x%" PRIx16 ".", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(uint16_t)pdescr->param_opts.opt3); \
|
||||
is_correct = false; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (!is_correct) { \
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s), initialize.", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key); \
|
||||
err = mbc_master_set_parameter(cid, (char *)pdescr->param_key, \
|
||||
(uint8_t *)pinst, &type); \
|
||||
if (err != ESP_OK) { \
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(int)err, \
|
||||
(char *)esp_err_to_name(err)); \
|
||||
} else { \
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (..) write successful.", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(char *)pdescr->param_units); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(int)err, \
|
||||
(char *)esp_err_to_name(err)); \
|
||||
} \
|
||||
(err); \
|
||||
} \
|
||||
))
|
||||
|
||||
// User operation function to read slave values and check alarm
|
||||
static void master_operation_func(void *arg)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
float value = 0;
|
||||
bool alarm_state = false;
|
||||
const mb_parameter_descriptor_t* param_descriptor = NULL;
|
||||
|
||||
@ -142,103 +306,117 @@ static void master_operation_func(void *arg)
|
||||
|
||||
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
||||
// Read all found characteristics from slave(s)
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
|
||||
{
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++) {
|
||||
// Get data from parameters description table
|
||||
// and use this information to fill the characteristics description table
|
||||
// and having all required fields in just one table
|
||||
err = mbc_master_get_cid_info(cid, ¶m_descriptor);
|
||||
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) {
|
||||
void* temp_data_ptr = master_get_param_data(param_descriptor);
|
||||
void *temp_data_ptr = master_get_param_data(param_descriptor);
|
||||
assert(temp_data_ptr);
|
||||
uint8_t type = 0;
|
||||
if ((param_descriptor->param_type == PARAM_TYPE_ASCII) &&
|
||||
(param_descriptor->cid == CID_HOLD_TEST_REG)) {
|
||||
// Check for long array of registers of type PARAM_TYPE_ASCII
|
||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint32_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
// Initialize data of test array and write to slave
|
||||
if (*(uint32_t*)temp_data_ptr != 0xAAAAAAAA) {
|
||||
memset((void*)temp_data_ptr, 0xAA, param_descriptor->param_size);
|
||||
*(uint32_t*)temp_data_ptr = 0xAAAAAAAA;
|
||||
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx32 "), write successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else {
|
||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
||||
value = *(float*)temp_data_ptr;
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
value,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min))) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_U16_AB)
|
||||
&& (param_descriptor->cid <= CID_HOLD_U16_BA)) {
|
||||
// Check the uint16 parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint16_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx16 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint16_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_U8_A)
|
||||
&& (param_descriptor->cid <= CID_HOLD_U8_B)) {
|
||||
// Check the uint8 parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint16_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx16 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint16_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_UINT32_ABCD)
|
||||
&& (param_descriptor->cid <= CID_HOLD_UINT32_DCBA)) {
|
||||
// Check the uint32 parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint32_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %" PRIu32 " (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint32_t *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_FLOAT_ABCD)
|
||||
&& (param_descriptor->cid <= CID_HOLD_FLOAT_DCBA)) {
|
||||
// Check the float parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (float *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(float *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else if (param_descriptor->cid >= CID_HOLD_DOUBLE_ABCDEFGH) {
|
||||
// Check the double parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (double *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %lf (0x%" PRIx64 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(double *)temp_data_ptr,
|
||||
*(uint64_t *)temp_data_ptr);
|
||||
}
|
||||
#endif
|
||||
} else if (cid <= CID_HOLD_DATA_2) {
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (float *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(float *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
float value = *(float *)temp_data_ptr;
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min))) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
} else if ((cid >= CID_RELAY_P1) && (cid <= CID_DISCR_P1)) {
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint8_t *)temp_data_ptr) == ESP_OK) {
|
||||
uint8_t state = *(uint8_t *)temp_data_ptr;
|
||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
if ((state & param_descriptor->param_opts.opt2) == param_descriptor->param_opts.opt2) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
(const char *)rw_str,
|
||||
*(uint8_t *)temp_data_ptr);
|
||||
} else {
|
||||
uint8_t state = *(uint8_t*)temp_data_ptr;
|
||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
if ((state & param_descriptor->param_opts.opt2) == param_descriptor->param_opts.opt2) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
(const char*)rw_str,
|
||||
*(uint8_t*)temp_data_ptr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 "), unexpected value.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
(const char*)rw_str,
|
||||
*(uint8_t*)temp_data_ptr);
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
if (state & param_descriptor->param_opts.opt1) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
ESP_LOGE(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 "), unexpected value.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
(const char *)rw_str,
|
||||
*(uint8_t *)temp_data_ptr);
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
if (state & param_descriptor->param_opts.opt1) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
|
||||
@ -279,20 +457,19 @@ static esp_err_t master_init(void)
|
||||
"mb controller initialization fail.");
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail, returns(0x%x).", (int)err);
|
||||
err = mbc_master_setup((void*)&comm);
|
||||
err = mbc_master_setup((void *)&comm);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller setup fail, returns(0x%x).", (int)err);
|
||||
|
||||
// Set UART pin numbers
|
||||
err = uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD,
|
||||
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
|
||||
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);
|
||||
err = mbc_master_start();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller start fail, returned (0x%x).", (int)err);
|
||||
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err);
|
||||
// Set driver mode to Half Duplex
|
||||
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
|
@ -3,3 +3,4 @@ CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=400
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
|
@ -4,3 +4,4 @@ CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=400
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
|
@ -6,3 +6,4 @@ CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=400
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -29,7 +29,11 @@
|
||||
#define MB_REG_INPUT_START_AREA0 (INPUT_OFFSET(input_data0)) // register offset input area 0
|
||||
#define MB_REG_INPUT_START_AREA1 (INPUT_OFFSET(input_data4)) // register offset input area 1
|
||||
#define MB_REG_HOLDING_START_AREA0 (HOLD_OFFSET(holding_data0))
|
||||
#define MB_REG_HOLDING_START_AREA0_SIZE ((size_t)((HOLD_OFFSET(holding_data4) - HOLD_OFFSET(holding_data0)) << 1))
|
||||
#define MB_REG_HOLDING_START_AREA1 (HOLD_OFFSET(holding_data4))
|
||||
#define MB_REG_HOLDING_START_AREA1_SIZE ((size_t)((HOLD_OFFSET(holding_area1_end) - HOLD_OFFSET(holding_data4)) << 1))
|
||||
#define MB_REG_HOLDING_START_AREA2 (HOLD_OFFSET(holding_u8_a))
|
||||
#define MB_REG_HOLDING_START_AREA2_SIZE ((size_t)((HOLD_OFFSET(holding_area2_end) - HOLD_OFFSET(holding_u8_a)) << 1))
|
||||
|
||||
#define MB_PAR_INFO_GET_TOUT (10) // Timeout for get parameter info
|
||||
#define MB_CHAN_DATA_MAX_VAL (6)
|
||||
@ -41,6 +45,7 @@
|
||||
#define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR \
|
||||
| MB_EVENT_COILS_WR)
|
||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||
#define MB_TEST_VALUE 12345.0
|
||||
|
||||
static const char *TAG = "SLAVE_TEST";
|
||||
|
||||
@ -69,6 +74,44 @@ static void setup_reg_data(void)
|
||||
holding_reg_params.holding_data6 = 7.79;
|
||||
holding_reg_params.holding_data7 = 8.80;
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
mb_set_uint8_a((val_16_arr *)&holding_reg_params.holding_u8_a[0], (uint8_t)0x55);
|
||||
mb_set_uint8_a((val_16_arr *)&holding_reg_params.holding_u8_a[1], (uint8_t)0x55);
|
||||
mb_set_uint8_b((val_16_arr *)&holding_reg_params.holding_u8_b[0], (uint8_t)0x55);
|
||||
mb_set_uint8_b((val_16_arr *)&holding_reg_params.holding_u8_b[1], (uint8_t)0x55);
|
||||
mb_set_uint16_ab((val_16_arr *)&holding_reg_params.holding_u16_ab[1], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ab((val_16_arr *)&holding_reg_params.holding_u16_ab[0], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ba((val_16_arr *)&holding_reg_params.holding_u16_ba[0], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ba((val_16_arr *)&holding_reg_params.holding_u16_ba[1], (uint16_t)MB_TEST_VALUE);
|
||||
|
||||
mb_set_float_abcd((val_32_arr *)&holding_reg_params.holding_float_abcd[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_abcd((val_32_arr *)&holding_reg_params.holding_float_abcd[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_cdab((val_32_arr *)&holding_reg_params.holding_float_cdab[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_cdab((val_32_arr *)&holding_reg_params.holding_float_cdab[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_badc((val_32_arr *)&holding_reg_params.holding_float_badc[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_badc((val_32_arr *)&holding_reg_params.holding_float_badc[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_dcba((val_32_arr *)&holding_reg_params.holding_float_dcba[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_dcba((val_32_arr *)&holding_reg_params.holding_float_dcba[1], (float)MB_TEST_VALUE);
|
||||
|
||||
mb_set_uint32_abcd((val_32_arr *)&holding_reg_params.holding_uint32_abcd[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_abcd((val_32_arr *)&holding_reg_params.holding_uint32_abcd[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_cdab((val_32_arr *)&holding_reg_params.holding_uint32_cdab[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_cdab((val_32_arr *)&holding_reg_params.holding_uint32_cdab[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_badc((val_32_arr *)&holding_reg_params.holding_uint32_badc[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_badc((val_32_arr *)&holding_reg_params.holding_uint32_badc[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_dcba((val_32_arr *)&holding_reg_params.holding_uint32_dcba[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_dcba((val_32_arr *)&holding_reg_params.holding_uint32_dcba[1], (uint32_t)MB_TEST_VALUE);
|
||||
|
||||
mb_set_double_abcdefgh((val_64_arr *)&holding_reg_params.holding_double_abcdefgh[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_abcdefgh((val_64_arr *)&holding_reg_params.holding_double_abcdefgh[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_hgfedcba((val_64_arr *)&holding_reg_params.holding_double_hgfedcba[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_hgfedcba((val_64_arr *)&holding_reg_params.holding_double_hgfedcba[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_ghefcdab((val_64_arr *)&holding_reg_params.holding_double_ghefcdab[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_ghefcdab((val_64_arr *)&holding_reg_params.holding_double_ghefcdab[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_badcfehg((val_64_arr *)&holding_reg_params.holding_double_badcfehg[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_badcfehg((val_64_arr *)&holding_reg_params.holding_double_badcfehg[1], (double)MB_TEST_VALUE);
|
||||
#endif
|
||||
|
||||
coil_reg_params.coils_port0 = 0x55;
|
||||
coil_reg_params.coils_port1 = 0xAA;
|
||||
|
||||
@ -120,21 +163,33 @@ void app_main(void)
|
||||
reg_area.type = MB_PARAM_HOLDING; // Set type of register area
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA0; // Offset of register area in Modbus protocol
|
||||
reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
|
||||
// Set the size of register storage instance = 150 holding registers
|
||||
reg_area.size = (size_t)(HOLD_OFFSET(holding_data4) - HOLD_OFFSET(test_regs));
|
||||
// Set the size of register storage instance in bytes
|
||||
reg_area.size = MB_REG_HOLDING_START_AREA0_SIZE;
|
||||
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
|
||||
|
||||
// The second register area
|
||||
reg_area.type = MB_PARAM_HOLDING; // Set type of register area
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol
|
||||
reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
|
||||
reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA1;
|
||||
reg_area.address = (void*)&holding_reg_params.holding_data4;
|
||||
reg_area.size = MB_REG_HOLDING_START_AREA1_SIZE;
|
||||
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
// The extended parameters register area
|
||||
reg_area.type = MB_PARAM_HOLDING;
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA2;
|
||||
reg_area.address = (void*)&holding_reg_params.holding_u8_a;
|
||||
reg_area.size = MB_REG_HOLDING_START_AREA2_SIZE;
|
||||
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
|
||||
#endif
|
||||
|
||||
// Initialization of Input Registers area
|
||||
reg_area.type = MB_PARAM_INPUT;
|
||||
reg_area.start_offset = MB_REG_INPUT_START_AREA0;
|
||||
reg_area.address = (void*)&input_reg_params.input_data0;
|
||||
reg_area.size = sizeof(float) << 2;
|
||||
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
|
||||
|
||||
reg_area.type = MB_PARAM_INPUT;
|
||||
reg_area.start_offset = MB_REG_INPUT_START_AREA1;
|
||||
reg_area.address = (void*)&input_reg_params.input_data4;
|
||||
@ -175,22 +230,21 @@ void app_main(void)
|
||||
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
|
||||
for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
|
||||
// Check for read/write events of Modbus master for certain events
|
||||
mb_event_group_t event = mbc_slave_check_event(MB_READ_WRITE_MASK);
|
||||
const char* rw_str = (event & MB_READ_MASK) ? "READ" : "WRITE";
|
||||
(void)mbc_slave_check_event(MB_READ_WRITE_MASK);
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
const char* rw_str = (reg_info.type & MB_READ_MASK) ? "READ" : "WRITE";
|
||||
|
||||
// Filter events and process them accordingly
|
||||
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||
if(reg_info.type & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||
// Get parameter information from parameter queue
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
ESP_LOGI(TAG, "HOLDING %s (%" PRIu32 " us), ADDR:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 ", SIZE:%u",
|
||||
rw_str,
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
if (reg_info.address == (uint8_t*)&holding_reg_params.holding_data0)
|
||||
{
|
||||
rw_str,
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
if (reg_info.address == (uint8_t*)&holding_reg_params.holding_data0) {
|
||||
portENTER_CRITICAL(¶m_lock);
|
||||
holding_reg_params.holding_data0 += MB_CHAN_DATA_OFFSET;
|
||||
if (holding_reg_params.holding_data0 >= (MB_CHAN_DATA_MAX_VAL - MB_CHAN_DATA_OFFSET)) {
|
||||
@ -198,31 +252,28 @@ void app_main(void)
|
||||
}
|
||||
portEXIT_CRITICAL(¶m_lock);
|
||||
}
|
||||
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
} else if (reg_info.type & MB_EVENT_INPUT_REG_RD) {
|
||||
ESP_LOGI(TAG, "INPUT READ (%" PRIu32 " us), ADDR:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 ", SIZE:%u",
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
} else if (event & MB_EVENT_DISCRETE_RD) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
} else if (reg_info.type & MB_EVENT_DISCRETE_RD) {
|
||||
ESP_LOGI(TAG, "DISCRETE READ (%" PRIu32 " us): ADDR:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 ", SIZE:%u",
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
} else if (reg_info.type & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
||||
ESP_LOGI(TAG, "COILS %s (%" PRIu32 " us), ADDR:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 ", SIZE:%u",
|
||||
rw_str,
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
rw_str,
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
if (coil_reg_params.coils_port1 == 0xFF) break;
|
||||
}
|
||||
}
|
||||
|
@ -2,3 +2,4 @@ CONFIG_MB_COMM_MODE_ASCII=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
|
@ -3,3 +3,4 @@ CONFIG_MB_COMM_MODE_RTU=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
|
@ -5,3 +5,4 @@ CONFIG_MB_COMM_MODE_ASCII=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
|
@ -2,4 +2,4 @@ set(PROJECT_NAME "modbus_tcp_master")
|
||||
|
||||
idf_component_register(SRCS "tcp_master.c"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
||||
|
@ -49,7 +49,16 @@
|
||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
||||
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
|
||||
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
|
||||
#define STR(fieldname) ((const char*)( fieldname ))
|
||||
|
||||
#define STR(fieldname) ((const char *)( fieldname ))
|
||||
#define TEST_HOLD_REG_START(field) (HOLD_OFFSET(field) >> 1)
|
||||
#define TEST_HOLD_REG_SIZE(field) (sizeof(((holding_reg_params_t *)0)->field) >> 1)
|
||||
|
||||
#define TEST_INPUT_REG_START(field) (INPUT_OFFSET(field) >> 1)
|
||||
#define TEST_INPUT_REG_SIZE(field) (sizeof(((input_reg_params_t *)0)->field) >> 1)
|
||||
|
||||
#define TEST_VALUE 12345 // default test value
|
||||
#define TEST_ASCII_BIN 0xAAAAAAAA
|
||||
|
||||
// Options can be used as bit masks or parameter limits
|
||||
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
|
||||
@ -68,6 +77,10 @@
|
||||
#endif
|
||||
|
||||
#define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp"
|
||||
|
||||
#define EACH_ITEM(array, length) \
|
||||
(typeof(*(array)) *pitem = (array); (pitem < &((array)[length])); pitem++)
|
||||
|
||||
static const char *TAG = "MASTER_TEST";
|
||||
|
||||
// Enumeration of modbus device addresses accessed by master device
|
||||
@ -90,6 +103,24 @@ enum {
|
||||
CID_RELAY_P1,
|
||||
CID_RELAY_P2,
|
||||
CID_DISCR_P1,
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
CID_HOLD_U8_A,
|
||||
CID_HOLD_U8_B,
|
||||
CID_HOLD_U16_AB,
|
||||
CID_HOLD_U16_BA,
|
||||
CID_HOLD_UINT32_ABCD,
|
||||
CID_HOLD_UINT32_CDAB,
|
||||
CID_HOLD_UINT32_BADC,
|
||||
CID_HOLD_UINT32_DCBA,
|
||||
CID_HOLD_FLOAT_ABCD,
|
||||
CID_HOLD_FLOAT_CDAB,
|
||||
CID_HOLD_FLOAT_BADC,
|
||||
CID_HOLD_FLOAT_DCBA,
|
||||
CID_HOLD_DOUBLE_ABCDEFGH,
|
||||
CID_HOLD_DOUBLE_HGFEDCBA,
|
||||
CID_HOLD_DOUBLE_GHEFCDAB,
|
||||
CID_HOLD_DOUBLE_BADCFEHG,
|
||||
#endif
|
||||
CID_COUNT
|
||||
};
|
||||
|
||||
@ -104,26 +135,109 @@ enum {
|
||||
// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc).
|
||||
const mb_parameter_descriptor_t device_parameters[] = {
|
||||
// { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
|
||||
{ CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
|
||||
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 1000, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
|
||||
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 2, 2,
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR2, MB_PARAM_INPUT, 4, 2,
|
||||
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR3, MB_PARAM_HOLDING, 4, 2,
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 10, 58,
|
||||
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 116, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data0), TEST_INPUT_REG_SIZE(input_data0),
|
||||
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data0), TEST_HOLD_REG_SIZE(holding_data0),
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data1), TEST_INPUT_REG_SIZE(input_data1),
|
||||
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( -40, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data1), TEST_HOLD_REG_SIZE(holding_data1),
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR2, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data2), TEST_INPUT_REG_SIZE(input_data2),
|
||||
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( -40, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR3, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data2), TEST_HOLD_REG_SIZE(holding_data2),
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( 0, 100, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(test_regs), 58,
|
||||
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 116,
|
||||
OPTS( 0, 100, TEST_ASCII_BIN ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 2, 6,
|
||||
COIL_OFFSET(coils_port0), PARAM_TYPE_U8, 1, OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
COIL_OFFSET(coils_port0), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_RELAY_P2, STR("RelayP2"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 10, 6,
|
||||
COIL_OFFSET(coils_port1), PARAM_TYPE_U8, 1, OPTS( 0x55, 0x2A, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
COIL_OFFSET(coils_port1), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0x55, 0x2A, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_DISCR_P1, STR("DiscreteInpP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_DISCRETE, 2, 7,
|
||||
DISCR_OFFSET(discrete_input_port1), PARAM_TYPE_U8, 1, OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER }
|
||||
DISCR_OFFSET(discrete_input_port1), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
{ CID_HOLD_U8_A, STR("U8_A"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u8_a), TEST_HOLD_REG_SIZE(holding_u8_a),
|
||||
HOLD_OFFSET(holding_u8_a), PARAM_TYPE_U8_A, (TEST_HOLD_REG_SIZE(holding_u8_a) << 1),
|
||||
OPTS( CHAR_MIN, 0x0055, 0x0055 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_U8_B, STR("U8_B"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u8_b), TEST_HOLD_REG_SIZE(holding_u8_b),
|
||||
HOLD_OFFSET(holding_u8_b), PARAM_TYPE_U8_B, (TEST_HOLD_REG_SIZE(holding_u8_b) << 1),
|
||||
OPTS( 0, 0x5500, 0x5500 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_U16_AB, STR("U16_AB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u16_ab), TEST_HOLD_REG_SIZE(holding_u16_ab),
|
||||
HOLD_OFFSET(holding_u16_ab), PARAM_TYPE_U16_AB, (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_U16_BA, STR("U16_BA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u16_ba), TEST_HOLD_REG_SIZE(holding_u16_ba),
|
||||
HOLD_OFFSET(holding_u16_ba), PARAM_TYPE_U16_BA, (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_ABCD, STR("UINT32_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_abcd), TEST_HOLD_REG_SIZE(holding_uint32_abcd),
|
||||
HOLD_OFFSET(holding_uint32_abcd), PARAM_TYPE_U32_ABCD, (TEST_HOLD_REG_SIZE(holding_uint32_abcd) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_CDAB, STR("UINT32_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_cdab), TEST_HOLD_REG_SIZE(holding_uint32_cdab),
|
||||
HOLD_OFFSET(holding_uint32_cdab), PARAM_TYPE_U32_CDAB, (TEST_HOLD_REG_SIZE(holding_uint32_cdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_BADC, STR("UINT32_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_badc), TEST_HOLD_REG_SIZE(holding_uint32_badc),
|
||||
HOLD_OFFSET(holding_uint32_badc), PARAM_TYPE_U32_BADC, (TEST_HOLD_REG_SIZE(holding_uint32_badc) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_UINT32_DCBA, STR("UINT32_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_dcba), TEST_HOLD_REG_SIZE(holding_uint32_dcba),
|
||||
HOLD_OFFSET(holding_uint32_dcba), PARAM_TYPE_U32_DCBA, (TEST_HOLD_REG_SIZE(holding_uint32_dcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_ABCD, STR("FLOAT_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_abcd), TEST_HOLD_REG_SIZE(holding_float_abcd),
|
||||
HOLD_OFFSET(holding_float_abcd), PARAM_TYPE_FLOAT_ABCD, (TEST_HOLD_REG_SIZE(holding_float_abcd) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_CDAB, STR("FLOAT_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_cdab), TEST_HOLD_REG_SIZE(holding_float_cdab),
|
||||
HOLD_OFFSET(holding_float_cdab), PARAM_TYPE_FLOAT_CDAB, (TEST_HOLD_REG_SIZE(holding_float_cdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_BADC, STR("FLOAT_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_badc), TEST_HOLD_REG_SIZE(holding_float_badc),
|
||||
HOLD_OFFSET(holding_float_badc), PARAM_TYPE_FLOAT_BADC, (TEST_HOLD_REG_SIZE(holding_float_badc) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_FLOAT_DCBA, STR("FLOAT_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_dcba), TEST_HOLD_REG_SIZE(holding_float_dcba),
|
||||
HOLD_OFFSET(holding_float_dcba), PARAM_TYPE_FLOAT_DCBA, (TEST_HOLD_REG_SIZE(holding_float_dcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_ABCDEFGH, STR("DOUBLE_ABCDEFGH"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_abcdefgh), TEST_HOLD_REG_SIZE(holding_double_abcdefgh),
|
||||
HOLD_OFFSET(holding_double_abcdefgh), PARAM_TYPE_DOUBLE_ABCDEFGH, (TEST_HOLD_REG_SIZE(holding_double_abcdefgh) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_HGFEDCBA, STR("DOUBLE_HGFEDCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_hgfedcba), TEST_HOLD_REG_SIZE(holding_double_hgfedcba),
|
||||
HOLD_OFFSET(holding_double_hgfedcba), PARAM_TYPE_DOUBLE_HGFEDCBA, (TEST_HOLD_REG_SIZE(holding_double_hgfedcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_GHEFCDAB, STR("DOUBLE_GHEFCDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_ghefcdab), TEST_HOLD_REG_SIZE(holding_double_ghefcdab),
|
||||
HOLD_OFFSET(holding_double_ghefcdab), PARAM_TYPE_DOUBLE_GHEFCDAB, (TEST_HOLD_REG_SIZE(holding_double_ghefcdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DOUBLE_BADCFEHG, STR("DOUBLE_BADCFEHG"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_badcfehg), TEST_HOLD_REG_SIZE(holding_double_badcfehg),
|
||||
HOLD_OFFSET(holding_double_badcfehg), PARAM_TYPE_DOUBLE_BADCFEHG, (TEST_HOLD_REG_SIZE(holding_double_badcfehg) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER }
|
||||
#endif
|
||||
};
|
||||
|
||||
// Calculate number of parameters in the table
|
||||
@ -480,11 +594,62 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
|
||||
return instance_ptr;
|
||||
}
|
||||
|
||||
#define TEST_VERIFY_VALUES(pdescr, pinst) (__extension__( \
|
||||
{ \
|
||||
assert(pinst); \
|
||||
assert(pdescr); \
|
||||
uint8_t type = 0; \
|
||||
esp_err_t err = ESP_FAIL; \
|
||||
err = mbc_master_get_parameter(pdescr->cid, (char *)pdescr->param_key, \
|
||||
(uint8_t *)pinst, &type); \
|
||||
if (err == ESP_OK) { \
|
||||
bool is_correct = true; \
|
||||
if (pdescr->param_opts.opt3) { \
|
||||
for EACH_ITEM(pinst, pdescr->param_size / sizeof(*pitem)) { \
|
||||
if (*pitem != (typeof(*(pinst)))pdescr->param_opts.opt3) { \
|
||||
*pitem = (typeof(*(pinst)))pdescr->param_opts.opt3; \
|
||||
ESP_LOGD(TAG, "Characteristic #%d (%s), initialize to 0x%" PRIx16 ".", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(uint16_t)pdescr->param_opts.opt3); \
|
||||
is_correct = false; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (!is_correct) { \
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s), initialize.", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key); \
|
||||
err = mbc_master_set_parameter(cid, (char *)pdescr->param_key, \
|
||||
(uint8_t *)pinst, &type); \
|
||||
if (err != ESP_OK) { \
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(int)err, \
|
||||
(char *)esp_err_to_name(err)); \
|
||||
} else { \
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (..) write successful.", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(char *)pdescr->param_units); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).", \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(int)err, \
|
||||
(char *)esp_err_to_name(err)); \
|
||||
} \
|
||||
(err); \
|
||||
} \
|
||||
))
|
||||
|
||||
// User operation function to read slave values and check alarm
|
||||
static void master_operation_func(void *arg)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
float value = 0;
|
||||
bool alarm_state = false;
|
||||
const mb_parameter_descriptor_t* param_descriptor = NULL;
|
||||
|
||||
@ -492,103 +657,117 @@ static void master_operation_func(void *arg)
|
||||
|
||||
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
||||
// Read all found characteristics from slave(s)
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
|
||||
{
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++) {
|
||||
// Get data from parameters description table
|
||||
// and use this information to fill the characteristics description table
|
||||
// and having all required fields in just one table
|
||||
err = mbc_master_get_cid_info(cid, ¶m_descriptor);
|
||||
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) {
|
||||
void* temp_data_ptr = master_get_param_data(param_descriptor);
|
||||
void *temp_data_ptr = master_get_param_data(param_descriptor);
|
||||
assert(temp_data_ptr);
|
||||
uint8_t type = 0;
|
||||
if ((param_descriptor->param_type == PARAM_TYPE_ASCII) &&
|
||||
(param_descriptor->cid == CID_HOLD_TEST_REG)) {
|
||||
// Check for long array of registers of type PARAM_TYPE_ASCII
|
||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint32_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
// Initialize data of test array and write to slave
|
||||
if (*(uint32_t*)temp_data_ptr != 0xAAAAAAAA) {
|
||||
memset((void*)temp_data_ptr, 0xAA, param_descriptor->param_size);
|
||||
*(uint32_t*)temp_data_ptr = 0xAAAAAAAA;
|
||||
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx32 "), write successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else {
|
||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
||||
value = *(float*)temp_data_ptr;
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
value,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min))) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_U16_AB)
|
||||
&& (param_descriptor->cid <= CID_HOLD_U16_BA)) {
|
||||
// Check the uint16 parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint16_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx16 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint16_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_U8_A)
|
||||
&& (param_descriptor->cid <= CID_HOLD_U8_B)) {
|
||||
// Check the uint8 parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint16_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx16 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint16_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_UINT32_ABCD)
|
||||
&& (param_descriptor->cid <= CID_HOLD_UINT32_DCBA)) {
|
||||
// Check the uint32 parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint32_t *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %" PRIu32 " (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint32_t *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_FLOAT_ABCD)
|
||||
&& (param_descriptor->cid <= CID_HOLD_FLOAT_DCBA)) {
|
||||
// Check the float parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (float *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(float *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else if (param_descriptor->cid >= CID_HOLD_DOUBLE_ABCDEFGH) {
|
||||
// Check the double parameters
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (double *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %lf (0x%" PRIx64 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(double *)temp_data_ptr,
|
||||
*(uint64_t *)temp_data_ptr);
|
||||
}
|
||||
#endif
|
||||
} else if (cid <= CID_HOLD_DATA_2) {
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (float *)temp_data_ptr) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(float *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
float value = *(float *)temp_data_ptr;
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min))) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
} else if ((cid >= CID_RELAY_P1) && (cid <= CID_DISCR_P1)) {
|
||||
if (TEST_VERIFY_VALUES(param_descriptor, (uint8_t *)temp_data_ptr) == ESP_OK) {
|
||||
uint8_t state = *(uint8_t *)temp_data_ptr;
|
||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
if ((state & param_descriptor->param_opts.opt2) == param_descriptor->param_opts.opt2) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
(const char *)rw_str,
|
||||
*(uint8_t *)temp_data_ptr);
|
||||
} else {
|
||||
uint8_t state = *(uint8_t*)temp_data_ptr;
|
||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
if ((state & param_descriptor->param_opts.opt2) == param_descriptor->param_opts.opt2) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 ") read successful.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
(const char*)rw_str,
|
||||
*(uint8_t*)temp_data_ptr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 "), unexpected value.",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
(const char*)rw_str,
|
||||
*(uint8_t*)temp_data_ptr);
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
if (state & param_descriptor->param_opts.opt1) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
ESP_LOGE(TAG, "Characteristic #%d %s (%s) value = %s (0x%" PRIx8 "), unexpected value.",
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
(const char *)rw_str,
|
||||
*(uint8_t *)temp_data_ptr);
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
if (state & param_descriptor->param_opts.opt1) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
|
||||
@ -754,6 +933,7 @@ void app_main(void)
|
||||
#else
|
||||
ip_addr_type = MB_IPV6;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(init_services(ip_addr_type));
|
||||
|
||||
mb_communication_info_t comm_info = { 0 };
|
||||
|
@ -12,6 +12,7 @@ CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=3000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
|
@ -7,6 +7,7 @@ CONFIG_FMB_COMM_MODE_RTU_EN=n
|
||||
CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=3000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
|
@ -11,6 +11,7 @@ CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=2000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
|
@ -2,4 +2,4 @@ set(PROJECT_NAME "modbus_tcp_slave")
|
||||
|
||||
idf_component_register(SRCS "tcp_slave.c"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -38,7 +38,11 @@
|
||||
#define MB_REG_INPUT_START_AREA0 (INPUT_OFFSET(input_data0)) // register offset input area 0
|
||||
#define MB_REG_INPUT_START_AREA1 (INPUT_OFFSET(input_data4)) // register offset input area 1
|
||||
#define MB_REG_HOLDING_START_AREA0 (HOLD_OFFSET(holding_data0))
|
||||
#define MB_REG_HOLDING_START_AREA0_SIZE ((size_t)((HOLD_OFFSET(holding_data4) - HOLD_OFFSET(holding_data0)) << 1))
|
||||
#define MB_REG_HOLDING_START_AREA1 (HOLD_OFFSET(holding_data4))
|
||||
#define MB_REG_HOLDING_START_AREA1_SIZE ((size_t)((HOLD_OFFSET(holding_area1_end) - HOLD_OFFSET(holding_data4)) << 1))
|
||||
#define MB_REG_HOLDING_START_AREA2 (HOLD_OFFSET(holding_u8_a))
|
||||
#define MB_REG_HOLDING_START_AREA2_SIZE ((size_t)((HOLD_OFFSET(holding_area2_end) - HOLD_OFFSET(holding_u8_a)) << 1))
|
||||
|
||||
#define MB_PAR_INFO_GET_TOUT (10) // Timeout for get parameter info
|
||||
#define MB_CHAN_DATA_MAX_VAL (10)
|
||||
@ -51,7 +55,7 @@
|
||||
#define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR \
|
||||
| MB_EVENT_COILS_WR)
|
||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||
|
||||
#define MB_TEST_VALUE 12345.0
|
||||
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
|
||||
|
||||
static const char *TAG = "SLAVE_TEST";
|
||||
@ -149,6 +153,45 @@ static void setup_reg_data(void)
|
||||
holding_reg_params.holding_data5 = 6.78;
|
||||
holding_reg_params.holding_data6 = 7.79;
|
||||
holding_reg_params.holding_data7 = 8.80;
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
mb_set_uint8_a((val_16_arr *)&holding_reg_params.holding_u8_a[0], (uint8_t)0x55);
|
||||
mb_set_uint8_a((val_16_arr *)&holding_reg_params.holding_u8_a[1], (uint8_t)0x55);
|
||||
mb_set_uint8_b((val_16_arr *)&holding_reg_params.holding_u8_b[0], (uint8_t)0x55);
|
||||
mb_set_uint8_b((val_16_arr *)&holding_reg_params.holding_u8_b[1], (uint8_t)0x55);
|
||||
mb_set_uint16_ab((val_16_arr *)&holding_reg_params.holding_u16_ab[1], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ab((val_16_arr *)&holding_reg_params.holding_u16_ab[0], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ba((val_16_arr *)&holding_reg_params.holding_u16_ba[0], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ba((val_16_arr *)&holding_reg_params.holding_u16_ba[1], (uint16_t)MB_TEST_VALUE);
|
||||
|
||||
mb_set_float_abcd((val_32_arr *)&holding_reg_params.holding_float_abcd[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_abcd((val_32_arr *)&holding_reg_params.holding_float_abcd[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_cdab((val_32_arr *)&holding_reg_params.holding_float_cdab[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_cdab((val_32_arr *)&holding_reg_params.holding_float_cdab[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_badc((val_32_arr *)&holding_reg_params.holding_float_badc[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_badc((val_32_arr *)&holding_reg_params.holding_float_badc[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_dcba((val_32_arr *)&holding_reg_params.holding_float_dcba[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_dcba((val_32_arr *)&holding_reg_params.holding_float_dcba[1], (float)MB_TEST_VALUE);
|
||||
|
||||
mb_set_uint32_abcd((val_32_arr *)&holding_reg_params.holding_uint32_abcd[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_abcd((val_32_arr *)&holding_reg_params.holding_uint32_abcd[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_cdab((val_32_arr *)&holding_reg_params.holding_uint32_cdab[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_cdab((val_32_arr *)&holding_reg_params.holding_uint32_cdab[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_badc((val_32_arr *)&holding_reg_params.holding_uint32_badc[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_badc((val_32_arr *)&holding_reg_params.holding_uint32_badc[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_dcba((val_32_arr *)&holding_reg_params.holding_uint32_dcba[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_dcba((val_32_arr *)&holding_reg_params.holding_uint32_dcba[1], (uint32_t)MB_TEST_VALUE);
|
||||
|
||||
mb_set_double_abcdefgh((val_64_arr *)&holding_reg_params.holding_double_abcdefgh[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_abcdefgh((val_64_arr *)&holding_reg_params.holding_double_abcdefgh[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_hgfedcba((val_64_arr *)&holding_reg_params.holding_double_hgfedcba[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_hgfedcba((val_64_arr *)&holding_reg_params.holding_double_hgfedcba[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_ghefcdab((val_64_arr *)&holding_reg_params.holding_double_ghefcdab[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_ghefcdab((val_64_arr *)&holding_reg_params.holding_double_ghefcdab[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_badcfehg((val_64_arr *)&holding_reg_params.holding_double_badcfehg[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_badcfehg((val_64_arr *)&holding_reg_params.holding_double_badcfehg[1], (double)MB_TEST_VALUE);
|
||||
#endif
|
||||
|
||||
coil_reg_params.coils_port0 = 0x55;
|
||||
coil_reg_params.coils_port1 = 0xAA;
|
||||
|
||||
@ -172,12 +215,13 @@ static void slave_operation_func(void *arg)
|
||||
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
|
||||
for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
|
||||
// Check for read/write events of Modbus master for certain events
|
||||
mb_event_group_t event = mbc_slave_check_event(MB_READ_WRITE_MASK);
|
||||
const char* rw_str = (event & MB_READ_MASK) ? "READ" : "WRITE";
|
||||
(void)mbc_slave_check_event(MB_READ_WRITE_MASK);
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
const char* rw_str = (reg_info.type & MB_READ_MASK) ? "READ" : "WRITE";
|
||||
|
||||
// Filter events and process them accordingly
|
||||
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||
if(reg_info.type & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||
// Get parameter information from parameter queue
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
rw_str,
|
||||
(unsigned)reg_info.time_stamp,
|
||||
@ -194,24 +238,21 @@ static void slave_operation_func(void *arg)
|
||||
}
|
||||
portEXIT_CRITICAL(¶m_lock);
|
||||
}
|
||||
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
} else if (reg_info.type & MB_EVENT_INPUT_REG_RD) {
|
||||
ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
(unsigned)reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(int)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
} else if (event & MB_EVENT_DISCRETE_RD) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
} else if (reg_info.type & MB_EVENT_DISCRETE_RD) {
|
||||
ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
(unsigned)reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(int)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
} else if (reg_info.type & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
||||
ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
rw_str,
|
||||
(unsigned)reg_info.time_stamp,
|
||||
@ -336,19 +377,32 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
reg_area.size = (MB_REG_HOLDING_START_AREA1 - MB_REG_HOLDING_START_AREA0) << 1; // Set the size of register storage instance
|
||||
err = mbc_slave_set_descriptor(reg_area);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(int)err);
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(int)err);
|
||||
|
||||
reg_area.type = MB_PARAM_HOLDING; // Set type of register area
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol
|
||||
reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
|
||||
reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
|
||||
reg_area.address = (void*)&holding_reg_params.holding_data4;
|
||||
reg_area.size = MB_REG_HOLDING_START_AREA1_SIZE;
|
||||
err = mbc_slave_set_descriptor(reg_area);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(int)err);
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(int)err);
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
// The extended parameters register area
|
||||
reg_area.type = MB_PARAM_HOLDING;
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA2;
|
||||
reg_area.address = (void*)&holding_reg_params.holding_u8_a;
|
||||
reg_area.size = MB_REG_HOLDING_START_AREA2_SIZE;
|
||||
err = mbc_slave_set_descriptor(reg_area);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(int)err);
|
||||
#endif
|
||||
|
||||
// Initialization of Input Registers area
|
||||
reg_area.type = MB_PARAM_INPUT;
|
||||
|
@ -13,6 +13,7 @@ CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TIMER_PORT_ENABLED=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
|
@ -7,6 +7,7 @@ CONFIG_FMB_COMM_MODE_RTU_EN=n
|
||||
CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=3000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
|
@ -11,6 +11,7 @@ CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=2000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
|
Reference in New Issue
Block a user