forked from espressif/esp-modbus
Compare commits
63 Commits
idf-extrac
...
bugfix/fix
Author | SHA1 | Date | |
---|---|---|---|
b9140da683 | |||
6cdcc8e337 | |||
38f64e5299 | |||
7a19da9016 | |||
5fa0b710d1 | |||
10618c3d64 | |||
d311198e26 | |||
bf34b5bb8d | |||
2d79f8cc67 | |||
906a437248 | |||
680d2cb4a8 | |||
7cdafc2468 | |||
e943cec30f | |||
7183cc5f52 | |||
cd34b914d3 | |||
52b692293b | |||
7d16826aef | |||
1741a27a87 | |||
8e3771847f | |||
2db0cfcf69 | |||
15e24c16b9 | |||
f18a0409a1 | |||
cea014cad1 | |||
234fbcf641 | |||
a854d3b188 | |||
3d386c942e | |||
f48f361dc6 | |||
926b10e7cb | |||
3f6537fc94 | |||
6e1c088e15 | |||
2540becd42 | |||
e491b161d5 | |||
7a064f6851 | |||
aca48fa758 | |||
cb1a315ee5 | |||
0e1fe58fbf | |||
e18c4fb329 | |||
77c2646f53 | |||
d42604ab82 | |||
8370c9e962 | |||
c5c6a7788d | |||
9ab2c68e84 | |||
fc8a50297d | |||
556d3ad512 | |||
b324ba8436 | |||
71cc71b3fe | |||
5a55930b02 | |||
0b1f0d41d9 | |||
1795c6476f | |||
28ebfb1712 | |||
9f58c2518d | |||
40a2161320 | |||
4bc17965ac | |||
72c889b2c9 | |||
29254b2b86 | |||
db34247764 | |||
a3cae7dca8 | |||
d9397a9c85 | |||
0faa194efd | |||
96316533a6 | |||
a9b0ba2eda | |||
3892c77c26 | |||
963c3dc5b0 |
186
.gitlab-ci.yml
186
.gitlab-ci.yml
@ -1,11 +1,13 @@
|
||||
stages:
|
||||
- build
|
||||
- target_test
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
# System environment
|
||||
ESP_DOCS_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env-v5.0:2-2"
|
||||
ESP_DOCS_PATH: "$CI_PROJECT_DIR"
|
||||
TEST_DIR: "$CI_PROJECT_DIR/test"
|
||||
|
||||
# GitLab-CI environment
|
||||
GET_SOURCES_ATTEMPTS: "10"
|
||||
@ -28,58 +30,153 @@ after_script:
|
||||
# Just for cleaning space, no other causes
|
||||
- git clean -ffdx
|
||||
|
||||
|
||||
# This template gets expanded multiple times, once for every IDF version.
|
||||
# IDF version is specified by setting the espressif/idf image tag.
|
||||
#
|
||||
# EXAMPLE_TARGETS sets the list of IDF_TARGET values to build examples for.
|
||||
# It should be equal to the list of targets supported by the specific IDF version.
|
||||
#
|
||||
# TEST_TARGETS sets the list of IDF_TARGET values to build the test_app for.
|
||||
# It should contain only the targets with optimized assembly implementations.
|
||||
#
|
||||
.build_template:
|
||||
stage: build
|
||||
tags:
|
||||
- build
|
||||
- internet
|
||||
script:
|
||||
- ./build_all.sh
|
||||
variables:
|
||||
EXAMPLE_TARGETS: "esp32"
|
||||
SIZE_INFO_LOCATION: "${TEST_DIR}/size_info.txt"
|
||||
IDF_CCACHE_ENABLE: "1"
|
||||
after_script:
|
||||
# Show ccache statistics if enabled globally
|
||||
- test "$CI_CCACHE_STATS" == 1 && test -n "$(which ccache)" && ccache --show-stats || true
|
||||
dependencies: []
|
||||
|
||||
.before_script_build_jobs:
|
||||
before_script:
|
||||
- pip install idf-component-manager --upgrade
|
||||
- pip install "idf_build_apps~=1.0.1"
|
||||
|
||||
.check_idf_ver: &check_idf_ver |
|
||||
export IDF_PATH=$(find /opt -type d -name "*idf*" \
|
||||
\( -exec test -f '{}/tools/idf.py' \; -and -exec test -f '{}/tools/idf_tools.py' \; \
|
||||
\) -print -quit)
|
||||
if [ -z "${IDF_PATH}" ];then
|
||||
echo "IDF version is not found."
|
||||
else
|
||||
cd ${IDF_PATH}
|
||||
export IDF_DESCRIBE=$(git describe)
|
||||
export IDF_VERSION=${IDF_DESCRIBE%-*}
|
||||
echo "ESP-IDF: $IDF_VERSION" >> $TEST_DIR/idf_version_info.txt
|
||||
echo "ESP-IDF: $IDF_VERSION"
|
||||
fi
|
||||
|
||||
# This template gets expanded multiple times, once for every IDF version.
|
||||
# IDF version is specified by setting the espressif/idf image tag.
|
||||
#
|
||||
# TEST_TARGETS sets the list of IDF_TARGET values to build the test for.
|
||||
# It should contain only the targets with optimized assembly implementations.
|
||||
#
|
||||
.build_pytest_template:
|
||||
stage: build
|
||||
extends:
|
||||
- .build_template
|
||||
- .before_script_build_jobs
|
||||
artifacts:
|
||||
paths:
|
||||
- "**/build*/size.json"
|
||||
- "**/build*/build.log"
|
||||
- "**/build*/build_log.txt"
|
||||
- "**/build*/*.bin"
|
||||
- "**/build*/*.elf"
|
||||
- "**/build*/*.map"
|
||||
- "**/build*/flasher_args.json"
|
||||
- "**/build*/flash_project_args"
|
||||
- "**/build*/config/sdkconfig.json"
|
||||
- "**/build*/bootloader/*.bin"
|
||||
- "**/build*/partition_table/*.bin"
|
||||
- "**/idf_version_info.txt"
|
||||
- $SIZE_INFO_LOCATION
|
||||
when: always
|
||||
expire_in: 3 weeks
|
||||
script:
|
||||
# CI specific options start from "--collect-size-info xxx". could ignore when running locally
|
||||
# The script below will build all test applications defined in environment variable $TEST_TARGETS
|
||||
- *check_idf_ver
|
||||
- cd ${TEST_DIR}
|
||||
- python -m idf_build_apps build -v -p .
|
||||
--recursive
|
||||
--target all
|
||||
--default-build-targets ${TEST_TARGETS}
|
||||
--config "sdkconfig.ci.*=" --build-dir "build_@t_@w"
|
||||
--check-warnings
|
||||
--ignore-warning-file ../tools/ignore_build_warnings.txt
|
||||
--collect-size-info $SIZE_INFO_LOCATION
|
||||
--manifest-rootpath .
|
||||
--manifest-file .build-test-rules.yml
|
||||
--parallel-count ${CI_NODE_TOTAL:-1}
|
||||
--parallel-index ${CI_NODE_INDEX:-1}
|
||||
variables:
|
||||
TEST_TARGETS: "esp32"
|
||||
|
||||
build_idf_v4.1:
|
||||
extends: .build_template
|
||||
image: espressif/idf:release-v4.1
|
||||
|
||||
build_idf_v4.2:
|
||||
extends: .build_template
|
||||
image: espressif/idf:release-v4.2
|
||||
variables:
|
||||
EXAMPLE_TARGETS: "esp32 esp32s2"
|
||||
|
||||
build_idf_v4.3:
|
||||
extends: .build_template
|
||||
image: espressif/idf:release-v4.3
|
||||
variables:
|
||||
EXAMPLE_TARGETS: "esp32 esp32s2 esp32c3"
|
||||
|
||||
build_idf_v4.4:
|
||||
extends: .build_template
|
||||
image: espressif/idf:release-v4.4
|
||||
variables:
|
||||
EXAMPLE_TARGETS: "esp32 esp32s2 esp32s3 esp32c3"
|
||||
TEST_TARGETS: "esp32 esp32s3"
|
||||
|
||||
build_idf_latest:
|
||||
extends: .build_template
|
||||
build_idf_master:
|
||||
extends: .build_pytest_template
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
EXAMPLE_TARGETS: "esp32 esp32s2 esp32s3 esp32c3"
|
||||
TEST_TARGETS: "esp32 esp32s3"
|
||||
# GNU Make based build system is not supported starting from IDF v5.0
|
||||
SKIP_GNU_MAKE_BUILD: 1
|
||||
TEST_TARGETS: "esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2"
|
||||
|
||||
build_idf_v5.0:
|
||||
extends: .build_pytest_template
|
||||
image: espressif/idf:release-v5.0
|
||||
variables:
|
||||
TEST_TARGETS: "esp32 esp32s2 esp32s3 esp32c2 esp32c3"
|
||||
|
||||
build_idf_v4.4:
|
||||
extends: .build_pytest_template
|
||||
image: espressif/idf:release-v4.4
|
||||
variables:
|
||||
TEST_TARGETS: "esp32 esp32s2 esp32s3 esp32c3"
|
||||
|
||||
.target_test_template:
|
||||
stage: target_test
|
||||
timeout: 1 hour
|
||||
variables:
|
||||
GIT_DEPTH: 1
|
||||
SUBMODULES_TO_FETCH: "none"
|
||||
cache:
|
||||
# Usually do not need submodule-cache in target_test
|
||||
- key: pip-cache
|
||||
paths:
|
||||
- .cache/pip
|
||||
policy: pull
|
||||
|
||||
.before_script_pytest_jobs:
|
||||
before_script:
|
||||
# Install pytest-embedded to perform test cases
|
||||
- pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf
|
||||
|
||||
.test_template:
|
||||
extends:
|
||||
- .before_script_pytest_jobs
|
||||
tags:
|
||||
- multi_dut_modbus_${TEST_PORT}
|
||||
artifacts:
|
||||
paths:
|
||||
- "${TEST_DIR}/*/*.log"
|
||||
- "${TEST_DIR}/*.txt"
|
||||
- "${TEST_DIR}/*/results_*.xml"
|
||||
- "${TEST_DIR}/pytest_embedded_log/"
|
||||
reports:
|
||||
junit: ${TEST_DIR}/${TEST_PORT}/results_${IDF_TARGET}_${IDF_BRANCH}.xml
|
||||
when: always
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${TEST_DIR}/${TEST_PORT}
|
||||
- echo "Start 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
|
||||
|
||||
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]
|
||||
parallel:
|
||||
matrix:
|
||||
- IDF_BRANCH: ["master", "v4.4", "v5.0"]
|
||||
IDF_TARGET: ["esp32"]
|
||||
TEST_PORT: ["serial", "tcp"]
|
||||
after_script: []
|
||||
|
||||
build_docs:
|
||||
stage: build
|
||||
@ -97,7 +194,7 @@ build_docs:
|
||||
script:
|
||||
- cd docs
|
||||
- pip install -r requirements.txt
|
||||
- build-docs -l en -t esp32
|
||||
- ./generate_docs
|
||||
|
||||
.deploy_docs_template:
|
||||
stage: deploy
|
||||
@ -158,4 +255,3 @@ upload_to_component_manager:
|
||||
- pip install idf-component-manager
|
||||
- export IDF_COMPONENT_API_TOKEN=${ESP_MODBUS_API_KEY}
|
||||
- python -m idf_component_manager upload-component --allow-existing --name=esp-modbus --namespace=espressif
|
||||
|
||||
|
@ -69,4 +69,6 @@ endif()
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_INCLUDE_DIRS "${priv_include_dirs}"
|
||||
REQUIRES ${requires})
|
||||
REQUIRES ${requires}
|
||||
PRIV_REQUIRES esp_netif)
|
||||
|
||||
|
18
Kconfig
18
Kconfig
@ -16,7 +16,7 @@ menu "Modbus configuration"
|
||||
|
||||
config FMB_TCP_PORT_MAX_CONN
|
||||
int "Maximum allowed connections for TCP stack"
|
||||
range 1 6
|
||||
range 1 8
|
||||
default 5
|
||||
depends on FMB_COMM_MODE_TCP_EN
|
||||
help
|
||||
@ -34,6 +34,14 @@ menu "Modbus configuration"
|
||||
Modbus TCP connection timeout in seconds.
|
||||
Once expired the current connection with the client will be closed
|
||||
and Modbus slave will be waiting for new connection to accept.
|
||||
|
||||
config FMB_TCP_UID_ENABLED
|
||||
bool "Modbus TCP enable UID (Unit Identifier) support"
|
||||
default n
|
||||
depends on FMB_COMM_MODE_TCP_EN
|
||||
help
|
||||
If this option is set the Modbus stack uses UID (Unit Identifier) field in MBAP frame.
|
||||
Else the UID is ignored by master and slave.
|
||||
|
||||
config FMB_COMM_MODE_RTU_EN
|
||||
bool "Enable Modbus stack support for RTU mode"
|
||||
@ -49,8 +57,8 @@ menu "Modbus configuration"
|
||||
|
||||
config FMB_MASTER_TIMEOUT_MS_RESPOND
|
||||
int "Slave respond timeout (Milliseconds)"
|
||||
default 150
|
||||
range 50 3000
|
||||
default 3000
|
||||
range 150 15000
|
||||
help
|
||||
If master sends a frame which is not broadcast, it has to wait sometime for slave response.
|
||||
if slave is not respond in this time, the master will process timeout error.
|
||||
@ -58,7 +66,7 @@ menu "Modbus configuration"
|
||||
config FMB_MASTER_DELAY_MS_CONVERT
|
||||
int "Slave conversion delay (Milliseconds)"
|
||||
default 200
|
||||
range 50 400
|
||||
range 150 2000
|
||||
help
|
||||
If master sends a broadcast frame, it has to wait conversion time to delay,
|
||||
then master can send next frame.
|
||||
@ -99,7 +107,7 @@ menu "Modbus configuration"
|
||||
config FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS
|
||||
int "Response timeout for ASCII communication mode (ms)"
|
||||
default 1000
|
||||
range 300 2000
|
||||
range 200 5000
|
||||
depends on FMB_COMM_MODE_ASCII_EN
|
||||
help
|
||||
This option defines response timeout of slave in milliseconds for ASCII communication mode.
|
||||
|
@ -59,10 +59,15 @@ function build_for_targets
|
||||
|
||||
echo "${STARS}"
|
||||
echo "Building in $PWD with CMake for ${IDF_TARGET}"
|
||||
preview_target=
|
||||
if [[ ${IDF_TARGET} == "esp32c6" ]]
|
||||
then
|
||||
preview_target="--preview"
|
||||
fi
|
||||
if [[ ${IDF_TARGET} != "esp32" ]]
|
||||
then
|
||||
# IDF 4.0 doesn't support idf.py set-target, and only supports esp32.
|
||||
idf.py set-target "${IDF_TARGET}"
|
||||
idf.py ${preview_target} set-target "${IDF_TARGET}"
|
||||
fi
|
||||
idf.py build || die "CMake build in ${PWD} has failed for ${IDF_TARGET}"
|
||||
idf.py fullclean
|
||||
|
12
docs/_static/modbus_docs_versions.js
vendored
12
docs/_static/modbus_docs_versions.js
vendored
@ -1,16 +1,14 @@
|
||||
var DOCUMENTATION_VERSIONS = {
|
||||
DEFAULTS: { has_targets: true,
|
||||
supported_targets: [ "esp32", "esp32s2", "esp32s3", "esp32c3" ]
|
||||
},
|
||||
VERSIONS: [
|
||||
{ name: "latest" },
|
||||
{ name: "v1.0.1", old:false },
|
||||
{ name: "v1.0.0", old:true }
|
||||
{ name: "latest", has_targets: true, supported_targets: [ "esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2" ] },
|
||||
],
|
||||
IDF_TARGETS: [
|
||||
{ text: "ESP32", value: "esp32"},
|
||||
{ text: "ESP32-S2", value: "esp32s2"},
|
||||
{ text: "ESP32-S3", value: "esp32s3"},
|
||||
{ text: "ESP32-C3", value: "esp32c3"}
|
||||
{ text: "ESP32-C2", value: "esp32c2"},
|
||||
{ text: "ESP32-C3", value: "esp32c3"},
|
||||
{ text: "ESP32-C6", value: "esp32c6"},
|
||||
{ text: "ESP32-H2", value: "esp32h2"}
|
||||
]
|
||||
};
|
||||
|
@ -1,3 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Common (non-language-specific) configuration for Sphinx
|
||||
#
|
||||
|
||||
# type: ignore
|
||||
# pylint: disable=wildcard-import
|
||||
# pylint: disable=undefined-variable
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
from esp_docs.conf_docs import * # noqa: F403,F401
|
||||
|
||||
extensions += ['sphinx_copybutton',
|
||||
@ -12,12 +23,11 @@ github_repo = 'espressif/esp-modbus'
|
||||
# context used by sphinx_idf_theme
|
||||
html_context['github_user'] = 'espressif'
|
||||
html_context['github_repo'] = 'esp-modbus'
|
||||
|
||||
html_static_path = ["../_static"]
|
||||
html_static_path = ['../_static']
|
||||
|
||||
# Extra options required by sphinx_idf_theme
|
||||
project_slug = 'esp-modbus'
|
||||
versions_url = './_static/modbus_docs_versions.js'
|
||||
|
||||
idf_targets = ['esp32', 'esp32s2', 'esp32c3']
|
||||
idf_targets = [ 'esp32' ]
|
||||
languages = ['en']
|
||||
|
27
docs/generate_docs
Executable file
27
docs/generate_docs
Executable file
@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf docs
|
||||
build-docs --target esp32 --language en
|
||||
|
||||
# Modifes target field of html files
|
||||
ELEMENT="<script type='text/javascript'>
|
||||
window.onload =(function() {
|
||||
var myAnchor = document.getElementById('target-select');
|
||||
var mySpan = document.createElement('input');
|
||||
mySpan.style.float = 'left';
|
||||
mySpan.setAttribute('type', 'text');
|
||||
mySpan.setAttribute('maxLength', '10');
|
||||
mySpan.value = 'all targets';
|
||||
mySpan.setAttribute('disabled', true);
|
||||
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
|
||||
})();
|
||||
</script>"
|
||||
|
||||
FILES=$(find . -path "*/_build/en/esp32/html/*.html")
|
||||
|
||||
for FILE in ${FILES}
|
||||
do
|
||||
echo ${ELEMENT} >> "${FILE}"
|
||||
done
|
||||
|
||||
|
@ -36,7 +36,7 @@ esp_err_t mbc_master_destroy(void)
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master destroy failure, error=(0x%x).",
|
||||
error);
|
||||
(int)error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ esp_err_t mbc_master_get_cid_info(uint16_t cid, const mb_parameter_descriptor_t*
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master get cid info failure, error=(0x%x).",
|
||||
error);
|
||||
(int)error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ esp_err_t mbc_master_get_parameter(uint16_t cid, char* name, uint8_t* value, uin
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master get parameter failure, error=(0x%x) (%s).",
|
||||
error, esp_err_to_name(error));
|
||||
(int)error, esp_err_to_name(error));
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ esp_err_t mbc_master_send_request(mb_param_request_t* request, void* data_ptr)
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master send request failure error=(0x%x) (%s).",
|
||||
error, esp_err_to_name(error));
|
||||
(int)error, esp_err_to_name(error));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ esp_err_t mbc_master_set_descriptor(const mb_parameter_descriptor_t* descriptor,
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master set descriptor failure, error=(0x%x) (%s).",
|
||||
error, esp_err_to_name(error));
|
||||
(int)error, esp_err_to_name(error));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ esp_err_t mbc_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uin
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master set parameter failure, error=(0x%x) (%s).",
|
||||
error, esp_err_to_name(error));
|
||||
(int)error, esp_err_to_name(error));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ esp_err_t mbc_master_setup(void* comm_info)
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master setup failure, error=(0x%x) (%s).",
|
||||
error, esp_err_to_name(error));
|
||||
(int)error, esp_err_to_name(error));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ esp_err_t mbc_master_start(void)
|
||||
MB_MASTER_CHECK((error == ESP_OK),
|
||||
error,
|
||||
"Master start failure, error=(0x%x) (%s).",
|
||||
error, esp_err_to_name(error));
|
||||
(int)error, esp_err_to_name(error));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ static void mbc_slave_free_descriptors(void) {
|
||||
mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts;
|
||||
|
||||
for (int descr_type = 0; descr_type < MB_PARAM_COUNT; descr_type++) {
|
||||
for (it = LIST_FIRST(&mbs_opts->mbs_area_descriptors[descr_type]); it != NULL; it = LIST_NEXT(it, entries)) {
|
||||
while ((it = LIST_FIRST(&mbs_opts->mbs_area_descriptors[descr_type]))) {
|
||||
LIST_REMOVE(it, entries);
|
||||
free(it);
|
||||
}
|
||||
@ -106,7 +106,7 @@ esp_err_t mbc_slave_destroy(void)
|
||||
MB_SLAVE_CHECK((error == ESP_OK),
|
||||
ESP_ERR_INVALID_STATE,
|
||||
"Slave destroy failure error=(0x%x).",
|
||||
error);
|
||||
(int)error);
|
||||
// Destroy all opened descriptors
|
||||
mbc_slave_free_descriptors();
|
||||
free(slave_interface_ptr);
|
||||
@ -130,7 +130,7 @@ esp_err_t mbc_slave_setup(void* comm_info)
|
||||
MB_SLAVE_CHECK((error == ESP_OK),
|
||||
ESP_ERR_INVALID_STATE,
|
||||
"Slave setup failure error=(0x%x).",
|
||||
error);
|
||||
(int)error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ esp_err_t mbc_slave_start(void)
|
||||
MB_SLAVE_CHECK((error == ESP_OK),
|
||||
ESP_ERR_INVALID_STATE,
|
||||
"Slave start failure error=(0x%x).",
|
||||
error);
|
||||
(int)error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ esp_err_t mbc_slave_get_param_info(mb_param_info_t* reg_info, uint32_t timeout)
|
||||
MB_SLAVE_CHECK((error == ESP_OK),
|
||||
ESP_ERR_INVALID_STATE,
|
||||
"Slave get parameter info failure error=(0x%x).",
|
||||
error);
|
||||
(int)error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ esp_err_t mbc_slave_set_descriptor(mb_register_area_descriptor_t descr_data)
|
||||
MB_SLAVE_CHECK((error == ESP_OK),
|
||||
ESP_ERR_INVALID_STATE,
|
||||
"Slave set descriptor failure error=(0x%x).",
|
||||
(uint16_t)error);
|
||||
(int)error);
|
||||
} else {
|
||||
mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts;
|
||||
// Check if the address is already in the descriptor list
|
||||
@ -252,8 +252,8 @@ static esp_err_t mbc_slave_send_param_info(mb_event_group_t par_type, uint16_t m
|
||||
par_info.mb_offset = mb_offset;
|
||||
BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, &par_info, MB_PAR_INFO_TOUT);
|
||||
if (pdTRUE == status) {
|
||||
ESP_LOGD(TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d",
|
||||
par_type, (uint32_t)par_address, par_size);
|
||||
ESP_LOGD(TAG, "Queue send parameter info (type, address, size): %d, 0x%" PRIx32 ", %u",
|
||||
(int)par_type, (uint32_t)par_address, (unsigned)par_size);
|
||||
error = ESP_OK;
|
||||
} else if (errQUEUE_FULL == status) {
|
||||
ESP_LOGD(TAG, "Parameter queue is overflowed.");
|
||||
@ -269,7 +269,7 @@ static esp_err_t mbc_slave_send_param_access_notification(mb_event_group_t event
|
||||
esp_err_t err = ESP_FAIL;
|
||||
mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, (EventBits_t)event);
|
||||
if (bits & event) {
|
||||
ESP_LOGD(TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event);
|
||||
ESP_LOGD(TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (int)event);
|
||||
err = ESP_OK;
|
||||
}
|
||||
return err;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef _MB_IFACE_COMMON_H
|
||||
#define _MB_IFACE_COMMON_H
|
||||
|
||||
#include <inttypes.h> // needs to be included for default system types (such as PRIxx)
|
||||
#include "driver/uart.h" // for UART types
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -23,11 +24,11 @@ extern "C" {
|
||||
|
||||
// if cannot include esp_check then use custom check macro
|
||||
|
||||
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) do { \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \
|
||||
return err_code; \
|
||||
} \
|
||||
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) do { \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(tag, "%s(%" PRIu32 "): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
@ -143,6 +144,7 @@ typedef union {
|
||||
// TCP/UDP communication structure
|
||||
struct {
|
||||
mb_mode_type_t ip_mode; /*!< Modbus communication mode */
|
||||
uint8_t slave_uid; /*!< Modbus slave address field for UID */
|
||||
uint16_t ip_port; /*!< Modbus port */
|
||||
mb_tcp_addr_type_t ip_addr_type; /*!< Modbus address type */
|
||||
void* ip_addr; /*!< Modbus address table for connection */
|
||||
|
@ -19,7 +19,7 @@ extern "C" {
|
||||
#define MB_MASTER_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
|
||||
|
||||
#define MB_MASTER_ASSERT(con) do { \
|
||||
if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
|
||||
if (!(con)) { ESP_LOGE(TAG, "assert errno:%u, errno_str: !(%s)", (unsigned)errno, strerror(errno)); assert(0 && #con); } \
|
||||
} while (0)
|
||||
|
||||
/*!
|
||||
|
@ -22,7 +22,7 @@ extern "C" {
|
||||
#define MB_SLAVE_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
|
||||
|
||||
#define MB_SLAVE_ASSERT(con) do { \
|
||||
if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
|
||||
if (!(con)) { ESP_LOGE(TAG, "assert errno:%u, errno_str: !(%s)", (unsigned)errno, strerror(errno)); assert(0 && #con); } \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
|
@ -154,11 +154,11 @@ eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||
UCHAR *pucMBASCIIFrame = ( UCHAR* ) ucASCIIBuf;
|
||||
USHORT usFrameLength = usRcvBufferPos;
|
||||
|
||||
if( xMBSerialPortGetRequest( &pucMBASCIIFrame, &usFrameLength ) == FALSE )
|
||||
if( xMBPortSerialGetRequest( &pucMBASCIIFrame, &usFrameLength ) == FALSE )
|
||||
{
|
||||
return MB_EIO;
|
||||
}
|
||||
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
assert( usFrameLength < MB_SER_PDU_SIZE_MAX );
|
||||
|
||||
@ -193,7 +193,7 @@ eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
UCHAR usLRC;
|
||||
|
||||
|
||||
|
||||
/* Check if the receiver is still in idle state. If not we where too
|
||||
* slow with processing the received frame and the master sent another
|
||||
* frame on the network. We have to abort sending the frame.
|
||||
@ -217,7 +217,7 @@ eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
eSndState = STATE_TX_START;
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
if ( xMBSerialPortSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE )
|
||||
if ( xMBPortSerialSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ eMBMasterASCIIStart( void )
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
eRcvState = STATE_M_RX_IDLE;
|
||||
vMBMasterPortSerialEnable( TRUE, FALSE );
|
||||
vMBMasterPortTimersT35Enable( );
|
||||
xMBMasterPortEventPost(EV_MASTER_READY);
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ eMBMasterASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLen
|
||||
UCHAR *pucMBASCIIFrame = ( UCHAR* ) ucMasterASCIIRcvBuf;
|
||||
USHORT usFrameLength = usMasterRcvBufferPos;
|
||||
|
||||
if( xMBMasterSerialPortGetResponse( &pucMBASCIIFrame, &usFrameLength ) == FALSE )
|
||||
if( xMBMasterPortSerialGetResponse( &pucMBASCIIFrame, &usFrameLength ) == FALSE )
|
||||
{
|
||||
return MB_EIO;
|
||||
}
|
||||
@ -181,8 +181,8 @@ eMBMasterASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLen
|
||||
|
||||
/* Return the start of the Modbus PDU to the caller. */
|
||||
*pucFrame = ( UCHAR * ) & pucMBASCIIFrame[MB_SER_PDU_PDU_OFF];
|
||||
} else {
|
||||
eStatus = MB_EIO;
|
||||
} else {
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
return eStatus;
|
||||
@ -219,7 +219,7 @@ eMBMasterASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLengt
|
||||
eSndState = STATE_M_TX_START;
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
if ( xMBMasterSerialPortSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE )
|
||||
if ( xMBMasterPortSerialSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
@ -274,8 +274,8 @@ xMBMasterASCIIReceiveFSM( void )
|
||||
usMasterRcvBufferPos = 0;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
eRcvState = STATE_M_RX_RCV;
|
||||
eSndState = STATE_M_TX_IDLE;
|
||||
}
|
||||
eSndState = STATE_M_TX_IDLE;
|
||||
break;
|
||||
|
||||
/* A new character is received. If the character is a ':' the input
|
||||
@ -437,7 +437,8 @@ xMBMasterASCIITransmitFSM( void )
|
||||
/* Notify the task which called eMBMasterASCIISend that the frame has
|
||||
* been sent. */
|
||||
case STATE_M_TX_NOTIFY:
|
||||
xFrameIsBroadcast = ( ucMasterASCIISndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
|
||||
xFrameIsBroadcast = ( ucMasterASCIISndBuf[MB_SEND_BUF_PDU_OFF - MB_SER_PDU_PDU_OFF]
|
||||
== MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
|
||||
vMBMasterRequestSetType( xFrameIsBroadcast );
|
||||
eSndState = STATE_M_TX_XFWR;
|
||||
/* If the frame is broadcast ,master will enable timer of convert delay,
|
||||
|
@ -110,7 +110,7 @@ eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils, LONG
|
||||
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF ] = usNCoils >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 1] = usNCoils;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
|
||||
}
|
||||
@ -217,7 +217,7 @@ eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LO
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF ] = usCoilData >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usCoilData;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
@ -327,7 +327,7 @@ eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
|
||||
*ucMBFrame++ = pucDataBuffer[usRegIndex++];
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + ucByteCount );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
|
@ -92,7 +92,7 @@ eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT u
|
||||
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF ] = usNDiscreteIn >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] = usNDiscreteIn;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
|
@ -122,7 +122,7 @@ eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRe
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
@ -200,7 +200,7 @@ eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
@ -286,7 +286,7 @@ eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRe
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
@ -392,7 +392,7 @@ eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
|
@ -93,7 +93,7 @@ eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
|
@ -165,6 +165,7 @@ eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
|
||||
* frame processing is still disabled until eMBEnable( ) is called.
|
||||
*
|
||||
* \param usTCPPort The TCP port to listen on.
|
||||
* \param ucSlaveUid The UID field for slave to listen on.
|
||||
* \return If the protocol stack has been initialized correctly the function
|
||||
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
|
||||
* codes is returned:
|
||||
@ -172,7 +173,7 @@ eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
|
||||
* slave addresses are in the range 1 - 247.
|
||||
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||
*/
|
||||
eMBErrorCode eMBTCPInit( USHORT usTCPPort );
|
||||
eMBErrorCode eMBTCPInit( UCHAR ucSlaveUid, USHORT usTCPPort );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Release resources used by the protocol stack.
|
||||
|
@ -103,7 +103,7 @@ typedef enum
|
||||
MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */
|
||||
MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */
|
||||
MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast ,then delay sometime.*/
|
||||
}eMBMasterTimerMode;
|
||||
} eMBMasterTimerMode;
|
||||
|
||||
/* ----------------------- Function prototypes ------------------------------*/
|
||||
/*! \ingroup modbus
|
||||
@ -408,6 +408,7 @@ BOOL xMBMasterRequestIsBroadcast( void );
|
||||
eMBMasterErrorEventType eMBMasterGetErrorType( void );
|
||||
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType );
|
||||
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void );
|
||||
eMBMode ucMBMasterGetCommMode( void );
|
||||
|
||||
/* ----------------------- Callback -----------------------------------------*/
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#ifndef _MB_CONFIG_H
|
||||
#define _MB_CONFIG_H
|
||||
|
||||
#include <inttypes.h> // needs to be included for default system types (such as PRIxx)
|
||||
#include "sdkconfig.h" // for KConfig options
|
||||
|
||||
#if __has_include("esp_idf_version.h")
|
||||
@ -86,6 +87,10 @@ PR_BEGIN_EXTERN_C
|
||||
|
||||
#endif
|
||||
|
||||
/*! \brief The option is required for support of RTU over TCP.
|
||||
*/
|
||||
#define MB_TCP_UID_ENABLED ( CONFIG_FMB_TCP_UID_ENABLED )
|
||||
|
||||
/*! \brief This option defines the number of data bits per ASCII character.
|
||||
*
|
||||
* A parity bit is added before the stop bit which keeps the actual byte size at 10 bits.
|
||||
@ -94,6 +99,9 @@ PR_BEGIN_EXTERN_C
|
||||
#define MB_ASCII_BITS_PER_SYMB ( CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB )
|
||||
#endif
|
||||
|
||||
#define MB_EVENT_QUEUE_SIZE ( CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE )
|
||||
#define MB_EVENT_QUEUE_TIMEOUT ( pdMS_TO_TICKS( CONFIG_FMB_EVENT_QUEUE_TIMEOUT ) )
|
||||
|
||||
/*! \brief The character timeout value for Modbus ASCII.
|
||||
*
|
||||
* The character timeout value is not fixed for Modbus ASCII and is therefore
|
||||
@ -167,7 +175,7 @@ PR_BEGIN_EXTERN_C
|
||||
#define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 )
|
||||
|
||||
/*! \brief Check the option to place timer handler into IRAM */
|
||||
#define MB_PORT_TIMER_ISR_IN_IRAM ( CONFIG_FMB_TIMER_ISR_IN_IRAM )
|
||||
#define MB_PORT_TIMER_ISR_IN_IRAM ( CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD )
|
||||
|
||||
/*! @} */
|
||||
#ifdef __cplusplus
|
||||
|
@ -87,6 +87,12 @@ PR_BEGIN_EXTERN_C
|
||||
#define MB_TCP_UID 6
|
||||
#define MB_TCP_FUNC 7
|
||||
|
||||
#if MB_MASTER_TCP_ENABLED
|
||||
#define MB_SEND_BUF_PDU_OFF MB_TCP_FUNC
|
||||
#else
|
||||
#define MB_SEND_BUF_PDU_OFF MB_SER_PDU_PDU_OFF
|
||||
#endif
|
||||
|
||||
#define MB_TCP_PSEUDO_ADDRESS 255
|
||||
|
||||
/* ----------------------- Prototypes 0-------------------------------------*/
|
||||
|
@ -50,12 +50,10 @@ PR_BEGIN_EXTERN_C
|
||||
#define MB_PORT_SERIAL_ISR_FLAG ESP_INTR_FLAG_LOWMED
|
||||
#endif
|
||||
|
||||
#if MB_PORT_TIMER_ISR_IN_IRAM
|
||||
#if CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD && MB_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
#define MB_PORT_ISR_ATTR IRAM_ATTR
|
||||
#define MB_PORT_TIMER_ISR_FLAG ESP_INTR_FLAG_IRAM
|
||||
#else
|
||||
#define MB_PORT_ISR_ATTR
|
||||
#define MB_PORT_TIMER_ISR_FLAG ESP_INTR_FLAG_LOWMED
|
||||
#endif
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
@ -72,17 +70,18 @@ typedef enum
|
||||
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
|
||||
typedef enum {
|
||||
EV_MASTER_NO_EVENT = 0x0000,
|
||||
EV_MASTER_READY = 0x0001, /*!< Startup finished. */
|
||||
EV_MASTER_FRAME_RECEIVED = 0x0002, /*!< Frame received. */
|
||||
EV_MASTER_EXECUTE = 0x0004, /*!< Execute function. */
|
||||
EV_MASTER_FRAME_SENT = 0x0008, /*!< Frame sent. */
|
||||
EV_MASTER_FRAME_TRANSMIT = 0x0010, /*!< Frame transmission. */
|
||||
EV_MASTER_ERROR_PROCESS = 0x0020, /*!< Frame error process. */
|
||||
EV_MASTER_PROCESS_SUCCESS = 0x0040, /*!< Request process success. */
|
||||
EV_MASTER_ERROR_RESPOND_TIMEOUT = 0x0080, /*!< Request respond timeout. */
|
||||
EV_MASTER_ERROR_RECEIVE_DATA = 0x0100, /*!< Request receive data error. */
|
||||
EV_MASTER_ERROR_EXECUTE_FUNCTION = 0x0200 /*!< Request execute function error. */
|
||||
} eMBMasterEventType;
|
||||
EV_MASTER_TRANS_START = 0x0001, /*!< Transaction start flag */
|
||||
EV_MASTER_READY = 0x0002, /*!< Startup finished. */
|
||||
EV_MASTER_FRAME_RECEIVED = 0x0004, /*!< Frame received. */
|
||||
EV_MASTER_EXECUTE = 0x0008, /*!< Execute function. */
|
||||
EV_MASTER_FRAME_SENT = 0x0010, /*!< Frame sent. */
|
||||
EV_MASTER_FRAME_TRANSMIT = 0x0020, /*!< Frame transmission. */
|
||||
EV_MASTER_ERROR_PROCESS = 0x0040, /*!< Frame error process. */
|
||||
EV_MASTER_PROCESS_SUCCESS = 0x0080, /*!< Request process success. */
|
||||
EV_MASTER_ERROR_RESPOND_TIMEOUT = 0x0100, /*!< Request respond timeout. */
|
||||
EV_MASTER_ERROR_RECEIVE_DATA = 0x0200, /*!< Request receive data error. */
|
||||
EV_MASTER_ERROR_EXECUTE_FUNCTION = 0x0400 /*!< Request execute function error. */
|
||||
} eMBMasterEventEnum;
|
||||
|
||||
typedef enum {
|
||||
EV_ERROR_INIT, /*!< No error, initial state. */
|
||||
@ -91,6 +90,14 @@ typedef enum {
|
||||
EV_ERROR_EXECUTE_FUNCTION, /*!< Execute function error. */
|
||||
EV_ERROR_OK /*!< No error, processing completed. */
|
||||
} eMBMasterErrorEventType;
|
||||
|
||||
typedef struct _MbEventType {
|
||||
eMBMasterEventEnum eEvent; /*!< event itself. */
|
||||
uint64_t xTransactionId; /*!< ID of the transaction */
|
||||
uint64_t xPostTimestamp; /*!< timestamp of event posted */
|
||||
uint64_t xGetTimestamp; /*!< timestamp of event get */
|
||||
} xMBMasterEventType;
|
||||
|
||||
#endif
|
||||
|
||||
/*! \ingroup modbus
|
||||
@ -117,18 +124,21 @@ BOOL xMBPortEventGet( /*@out@ */ eMBEventType * eEvent );
|
||||
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
|
||||
BOOL xMBMasterPortEventInit( void );
|
||||
|
||||
BOOL xMBMasterPortEventPost( eMBMasterEventType eEvent );
|
||||
BOOL xMBMasterPortEventPost( eMBMasterEventEnum eEvent );
|
||||
|
||||
BOOL xMBMasterPortEventGet( /*@out@ */ eMBMasterEventType * eEvent );
|
||||
BOOL xMBMasterPortEventGet( /*@out@ */ xMBMasterEventType * eEvent );
|
||||
|
||||
eMBMasterEventType
|
||||
xMBMasterPortFsmWaitConfirmation( eMBMasterEventType eEventMask, ULONG ulTimeout);
|
||||
eMBMasterEventEnum
|
||||
xMBMasterPortFsmWaitConfirmation( eMBMasterEventEnum eEventMask, ULONG ulTimeout);
|
||||
|
||||
void vMBMasterOsResInit( void );
|
||||
|
||||
BOOL xMBMasterRunResTake( LONG time );
|
||||
|
||||
void vMBMasterRunResRelease( void );
|
||||
|
||||
uint64_t xMBMasterPortGetTransactionId( void );
|
||||
|
||||
#endif // MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
|
||||
/* ----------------------- Serial port functions ----------------------------*/
|
||||
|
||||
@ -145,9 +155,9 @@ BOOL xMBPortSerialGetByte( CHAR * pucByte );
|
||||
|
||||
BOOL xMBPortSerialPutByte( CHAR ucByte );
|
||||
|
||||
BOOL xMBSerialPortGetRequest( UCHAR **ppucMBSerialFrame, USHORT * pusSerialLength ) __attribute__ ((weak));
|
||||
BOOL xMBPortSerialGetRequest( UCHAR **ppucMBSerialFrame, USHORT * pusSerialLength ) __attribute__ ((weak));
|
||||
|
||||
BOOL xMBSerialPortSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) __attribute__ ((weak));
|
||||
BOOL xMBPortSerialSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) __attribute__ ((weak));
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED
|
||||
BOOL xMBMasterPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
|
||||
@ -163,9 +173,11 @@ BOOL xMBMasterPortSerialGetByte( CHAR * pucByte );
|
||||
|
||||
BOOL xMBMasterPortSerialPutByte( CHAR ucByte );
|
||||
|
||||
BOOL xMBMasterSerialPortGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength );
|
||||
BOOL xMBMasterPortSerialGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength );
|
||||
|
||||
BOOL xMBMasterSerialPortSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength );
|
||||
BOOL xMBMasterPortSerialSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength );
|
||||
|
||||
void vMBMasterRxFlush( void );
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -62,7 +62,7 @@ PR_BEGIN_EXTERN_C
|
||||
#define MB_FUNC_OTHER_REPORT_SLAVEID ( 17 )
|
||||
#define MB_FUNC_ERROR ( 128u )
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
typedef enum
|
||||
typedef enum
|
||||
{
|
||||
MB_EX_NONE = 0x00,
|
||||
MB_EX_ILLEGAL_FUNCTION = 0x01,
|
||||
|
@ -202,11 +202,16 @@ eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eM
|
||||
|
||||
#if MB_TCP_ENABLED > 0
|
||||
eMBErrorCode
|
||||
eMBTCPInit( USHORT ucTCPPort )
|
||||
eMBTCPInit( UCHAR ucSlaveUid, USHORT ucTCPPort )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR )
|
||||
/* Check preconditions */
|
||||
if( ucSlaveUid > MB_ADDRESS_MAX )
|
||||
{
|
||||
eStatus = MB_EINVAL;
|
||||
}
|
||||
else if( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR )
|
||||
{
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
@ -222,7 +227,7 @@ eMBTCPInit( USHORT ucTCPPort )
|
||||
peMBFrameReceiveCur = eMBTCPReceive;
|
||||
peMBFrameSendCur = eMBTCPSend;
|
||||
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
|
||||
ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
|
||||
ucMBAddress = ucSlaveUid;
|
||||
eMBCurrentMode = MB_TCP;
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
@ -371,7 +376,8 @@ eMBPoll( void )
|
||||
if( eStatus == MB_ENOERR )
|
||||
{
|
||||
/* Check if the frame is for us. If not ignore the frame. */
|
||||
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
|
||||
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST )
|
||||
|| ( ucRcvAddress == MB_TCP_PSEUDO_ADDRESS ) )
|
||||
{
|
||||
( void )xMBPortEventPost( EV_EXECUTE );
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(MB_PORT_TAG, &ucMBFrame[MB_PDU_FUNC_OFF], usLength, ESP_LOG_DEBUG);
|
||||
@ -401,8 +407,8 @@ eMBPoll( void )
|
||||
}
|
||||
|
||||
/* If the request was not sent to the broadcast address we
|
||||
* return a reply. */
|
||||
if( ucRcvAddress != MB_ADDRESS_BROADCAST )
|
||||
* return a reply. In case of TCP the slave answers to broadcast address. */
|
||||
if( ( ucRcvAddress != MB_ADDRESS_BROADCAST ) || ( eMBCurrentMode == MB_TCP ) )
|
||||
{
|
||||
if( eException != MB_EX_NONE )
|
||||
{
|
||||
|
@ -36,8 +36,9 @@
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
@ -177,7 +178,7 @@ eMBMasterTCPInit( USHORT ucTCPPort )
|
||||
|
||||
// initialize the OS resource for modbus master.
|
||||
vMBMasterOsResInit();
|
||||
if( xMBMasterPortTimersInit( MB_MASTER_TIMEOUT_MS_RESPOND * MB_TIMER_TICS_PER_MS ) != TRUE )
|
||||
if (xMBMasterPortTimersInit(MB_MASTER_TIMEOUT_MS_RESPOND * MB_TIMER_TICS_PER_MS) != TRUE)
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
@ -310,160 +311,177 @@ eMBMasterDisable( void )
|
||||
eMBErrorCode
|
||||
eMBMasterPoll( void )
|
||||
{
|
||||
static UCHAR *ucMBFrame = NULL;
|
||||
static UCHAR *ucMBSendFrame = NULL;
|
||||
static UCHAR *ucMBRcvFrame = NULL;
|
||||
static UCHAR ucRcvAddress;
|
||||
static UCHAR ucFunctionCode;
|
||||
static USHORT usLength;
|
||||
static eMBException eException;
|
||||
static uint64_t xCurTransactionId = 0;
|
||||
int i;
|
||||
int j;
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
eMBMasterEventType eEvent;
|
||||
xMBMasterEventType xEvent;
|
||||
eMBMasterErrorEventType errorType;
|
||||
|
||||
/* Check if the protocol stack is ready. */
|
||||
if( eMBState != STATE_ENABLED )
|
||||
{
|
||||
if( eMBState != STATE_ENABLED ) {
|
||||
return MB_EILLSTATE;
|
||||
}
|
||||
|
||||
/* Check if there is a event available. If not return control to caller.
|
||||
* Otherwise we will handle the event. */
|
||||
if ( xMBMasterPortEventGet( &eEvent ) == TRUE )
|
||||
{
|
||||
while( eEvent ) {
|
||||
if ( xMBMasterPortEventGet( &xEvent ) == TRUE ) {
|
||||
switch( xEvent.eEvent ) {
|
||||
// In some cases it is possible that more than one event set
|
||||
// together (even from one subset mask) than process them consistently
|
||||
if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_READY ) ) {
|
||||
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_READY", __func__);
|
||||
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_READY );
|
||||
} else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_TRANSMIT ) ) {
|
||||
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_FRAME_TRANSMIT", __func__);
|
||||
case EV_MASTER_READY:
|
||||
ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_READY", xEvent.xTransactionId);
|
||||
vMBMasterSetErrorType( EV_ERROR_INIT );
|
||||
vMBMasterRunResRelease( );
|
||||
break;
|
||||
case EV_MASTER_FRAME_TRANSMIT:
|
||||
ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_TRANSMIT", xEvent.xTransactionId);
|
||||
/* Master is busy now. */
|
||||
vMBMasterGetPDUSndBuf( &ucMBFrame );
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("POLL transmit buffer", (void*)ucMBFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG);
|
||||
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
|
||||
if (eStatus != MB_ENOERR)
|
||||
{
|
||||
ESP_LOGE( MB_PORT_TAG, "%s:Frame send error. %d", __func__, eStatus );
|
||||
}
|
||||
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_TRANSMIT );
|
||||
} else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_SENT ) ) {
|
||||
ESP_LOGD( MB_PORT_TAG, "%s:EV_MASTER_FRAME_SENT", __func__ );
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("POLL sent buffer", (void*)ucMBFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG);
|
||||
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_SENT );
|
||||
} else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_RECEIVED ) ) {
|
||||
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength);
|
||||
|
||||
// Check if the frame is for us. If not ,send an error process event.
|
||||
if ( ( eStatus == MB_ENOERR ) && ( ( ucRcvAddress == ucMBMasterGetDestAddress() )
|
||||
|| ( ucRcvAddress == MB_TCP_PSEUDO_ADDRESS ) ) )
|
||||
{
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
|
||||
ESP_LOGD(MB_PORT_TAG, "%s: Packet data received successfully (%u).", __func__, eStatus);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)ucMBFrame, (uint16_t)usLength, ESP_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf( &ucMBSendFrame );
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("POLL transmit buffer", (void*)ucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG);
|
||||
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBSendFrame, usMBMasterGetPDUSndLength() );
|
||||
if (eStatus != MB_ENOERR) {
|
||||
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
ESP_LOGD( MB_PORT_TAG, "%s: Packet data receive failed (addr=%u)(%u).",
|
||||
__func__, ucRcvAddress, eStatus);
|
||||
ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":Frame send error = %d", xEvent.xTransactionId, (unsigned)eStatus );
|
||||
}
|
||||
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_RECEIVED );
|
||||
} else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_EXECUTE ) ) {
|
||||
if ( !ucMBFrame )
|
||||
{
|
||||
return MB_EILLSTATE;
|
||||
xCurTransactionId = xEvent.xTransactionId;
|
||||
break;
|
||||
case EV_MASTER_FRAME_SENT:
|
||||
if (xCurTransactionId == xEvent.xTransactionId) {
|
||||
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_SENT", xEvent.xTransactionId );
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("POLL sent buffer", (void*)ucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG);
|
||||
}
|
||||
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_EXECUTE", __func__);
|
||||
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
|
||||
eException = MB_EX_ILLEGAL_FUNCTION;
|
||||
/* If receive frame has exception. The receive function code highest bit is 1.*/
|
||||
if (ucFunctionCode & MB_FUNC_ERROR)
|
||||
{
|
||||
eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
|
||||
} else {
|
||||
for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
|
||||
{
|
||||
/* No more function handlers registered. Abort. */
|
||||
if (xMasterFuncHandlers[i].ucFunctionCode == 0)
|
||||
{
|
||||
break;
|
||||
break;
|
||||
case EV_MASTER_FRAME_RECEIVED:
|
||||
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_RECEIVED", xEvent.xTransactionId );
|
||||
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBRcvFrame, &usLength);
|
||||
if (xCurTransactionId == xEvent.xTransactionId) {
|
||||
MB_PORT_CHECK(ucMBSendFrame, MB_EILLSTATE, "Send buffer initialization fail.");
|
||||
// Check if the frame is for us. If not ,send an error process event.
|
||||
if ( ( eStatus == MB_ENOERR ) && ( ( ucRcvAddress == ucMBMasterGetDestAddress() )
|
||||
|| ( ucRcvAddress == MB_TCP_PSEUDO_ADDRESS) ) ) {
|
||||
if ( ( ucMBRcvFrame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR ) == ( ucMBSendFrame[MB_PDU_FUNC_OFF] ) ) {
|
||||
ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ": Packet data received successfully (%u).", xEvent.xTransactionId, (unsigned)eStatus);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)ucMBRcvFrame, (uint16_t)usLength, ESP_LOG_DEBUG);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
|
||||
} else {
|
||||
ESP_LOGE( MB_PORT_TAG, "Drop incorrect frame, receive_func(%u) != send_func(%u)",
|
||||
ucMBRcvFrame[MB_PDU_FUNC_OFF], ucMBSendFrame[MB_PDU_FUNC_OFF]);
|
||||
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
}
|
||||
if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode)
|
||||
{
|
||||
vMBMasterSetCBRunInMasterMode(TRUE);
|
||||
/* If master request is broadcast,
|
||||
* the master need execute function for all slave.
|
||||
*/
|
||||
if ( xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
usLength = usMBMasterGetPDUSndLength();
|
||||
for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++)
|
||||
{
|
||||
vMBMasterSetDestAddress(j);
|
||||
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eException = xMasterFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
|
||||
}
|
||||
vMBMasterSetCBRunInMasterMode( FALSE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If master has exception, will send error process event. Otherwise the master is idle.*/
|
||||
if ( eException != MB_EX_NONE )
|
||||
{
|
||||
vMBMasterSetErrorType( EV_ERROR_EXECUTE_FUNCTION );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( eMBMasterGetErrorType( ) == EV_ERROR_INIT ) {
|
||||
vMBMasterSetErrorType(EV_ERROR_OK);
|
||||
ESP_LOGD( MB_PORT_TAG, "%s: set event EV_ERROR_OK", __func__ );
|
||||
} else {
|
||||
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ": Packet data receive failed (addr=%u)(%u).",
|
||||
xEvent.xTransactionId, (unsigned)ucRcvAddress, (unsigned)eStatus);
|
||||
}
|
||||
} else {
|
||||
// Ignore the `EV_MASTER_FRAME_RECEIVED` event because the respond timeout occurred
|
||||
// and this is likely respond to previous transaction
|
||||
ESP_LOGE( MB_PORT_TAG, "Drop data received outside of transaction (%" PRIu64 ")", xEvent.xTransactionId );
|
||||
}
|
||||
break;
|
||||
case EV_MASTER_EXECUTE:
|
||||
if (xCurTransactionId == xEvent.xTransactionId) {
|
||||
MB_PORT_CHECK(ucMBRcvFrame, MB_EILLSTATE, "receive buffer initialization fail.");
|
||||
ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_EXECUTE", xEvent.xTransactionId);
|
||||
ucFunctionCode = ucMBRcvFrame[MB_PDU_FUNC_OFF];
|
||||
eException = MB_EX_ILLEGAL_FUNCTION;
|
||||
/* If receive frame has exception. The receive function code highest bit is 1.*/
|
||||
if (ucFunctionCode & MB_FUNC_ERROR) {
|
||||
eException = (eMBException)ucMBRcvFrame[MB_PDU_DATA_OFF];
|
||||
} else {
|
||||
for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
|
||||
{
|
||||
/* No more function handlers registered. Abort. */
|
||||
if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
|
||||
break;
|
||||
}
|
||||
if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
|
||||
vMBMasterSetCBRunInMasterMode(TRUE);
|
||||
/* If master request is broadcast,
|
||||
* the master need execute function for all slave.
|
||||
*/
|
||||
if ( xMBMasterRequestIsBroadcast() ) {
|
||||
usLength = usMBMasterGetPDUSndLength();
|
||||
for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++)
|
||||
{
|
||||
vMBMasterSetDestAddress(j);
|
||||
eException = xMasterFuncHandlers[i].pxHandler(ucMBRcvFrame, &usLength);
|
||||
}
|
||||
} else {
|
||||
eException = xMasterFuncHandlers[i].pxHandler( ucMBRcvFrame, &usLength );
|
||||
}
|
||||
vMBMasterSetCBRunInMasterMode( FALSE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If master has exception, will send error process event. Otherwise the master is idle.*/
|
||||
if ( eException != MB_EX_NONE ) {
|
||||
vMBMasterSetErrorType( EV_ERROR_EXECUTE_FUNCTION );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
} else {
|
||||
if ( eMBMasterGetErrorType( ) == EV_ERROR_INIT ) {
|
||||
vMBMasterSetErrorType(EV_ERROR_OK);
|
||||
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":set event EV_ERROR_OK", xEvent.xTransactionId );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_EXECUTE is expired", xEvent.xTransactionId );
|
||||
}
|
||||
break;
|
||||
case EV_MASTER_ERROR_PROCESS:
|
||||
if (xCurTransactionId == xEvent.xTransactionId) {
|
||||
ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_ERROR_PROCESS", xEvent.xTransactionId);
|
||||
/* Execute specified error process callback function. */
|
||||
errorType = eMBMasterGetErrorType( );
|
||||
vMBMasterGetPDUSndBuf( &ucMBSendFrame );
|
||||
switch ( errorType )
|
||||
{
|
||||
case EV_ERROR_RESPOND_TIMEOUT:
|
||||
vMBMasterErrorCBRespondTimeout( ucMBMasterGetDestAddress( ),
|
||||
ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
|
||||
break;
|
||||
case EV_ERROR_RECEIVE_DATA:
|
||||
vMBMasterErrorCBReceiveData( ucMBMasterGetDestAddress( ),
|
||||
ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
|
||||
break;
|
||||
case EV_ERROR_EXECUTE_FUNCTION:
|
||||
vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ),
|
||||
ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
|
||||
break;
|
||||
case EV_ERROR_OK:
|
||||
vMBMasterCBRequestSuccess( );
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":incorrect error type = %d.", xEvent.xTransactionId, (int)errorType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_EXECUTE );
|
||||
} else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_ERROR_PROCESS ) ) {
|
||||
ESP_LOGD( MB_PORT_TAG, "%s:EV_MASTER_ERROR_PROCESS", __func__ );
|
||||
/* Execute specified error process callback function. */
|
||||
errorType = eMBMasterGetErrorType( );
|
||||
vMBMasterGetPDUSndBuf( &ucMBFrame );
|
||||
switch ( errorType )
|
||||
{
|
||||
case EV_ERROR_RESPOND_TIMEOUT:
|
||||
vMBMasterErrorCBRespondTimeout( ucMBMasterGetDestAddress( ),
|
||||
ucMBFrame, usMBMasterGetPDUSndLength( ) );
|
||||
break;
|
||||
case EV_ERROR_RECEIVE_DATA:
|
||||
vMBMasterErrorCBReceiveData( ucMBMasterGetDestAddress( ),
|
||||
ucMBFrame, usMBMasterGetPDUSndLength( ) );
|
||||
break;
|
||||
case EV_ERROR_EXECUTE_FUNCTION:
|
||||
vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ),
|
||||
ucMBFrame, usMBMasterGetPDUSndLength( ) );
|
||||
break;
|
||||
case EV_ERROR_OK:
|
||||
vMBMasterCBRequestSuccess( );
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE( MB_PORT_TAG, "%s: incorrect error type = %d.", __func__, errorType);
|
||||
break;
|
||||
}
|
||||
vMBMasterPortTimersDisable( );
|
||||
uint64_t xProcTime = xCurTransactionId ? ( xEvent.xPostTimestamp - xCurTransactionId ) : 0;
|
||||
ESP_LOGD( MB_PORT_TAG, "Transaction (%" PRIu64 "), processing time(us) = %" PRId64, xCurTransactionId, xProcTime );
|
||||
xCurTransactionId = 0;
|
||||
vMBMasterSetErrorType( EV_ERROR_INIT );
|
||||
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_ERROR_PROCESS );
|
||||
vMBMasterRunResRelease( );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":Unexpected event triggered 0x%02x.", xEvent.xTransactionId, (int)xEvent.eEvent );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Something went wrong and task unblocked but there are no any correct events set
|
||||
ESP_LOGE( MB_PORT_TAG, "%s: Unexpected event triggered 0x%02x.", __func__, eEvent );
|
||||
ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ": Unexpected event triggered 0x%02x.", xEvent.xTransactionId, (int)xEvent.eEvent );
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
@ -472,67 +490,67 @@ eMBMasterPoll( void )
|
||||
// Get whether the Modbus Master is run in master mode.
|
||||
BOOL xMBMasterGetCBRunInMasterMode( void )
|
||||
{
|
||||
return xMBRunInMasterMode;
|
||||
return atomic_load(&xMBRunInMasterMode);
|
||||
}
|
||||
|
||||
// Set whether the Modbus Master is run in master mode.
|
||||
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode )
|
||||
{
|
||||
xMBRunInMasterMode = IsMasterMode;
|
||||
atomic_store(&(xMBRunInMasterMode), IsMasterMode);
|
||||
}
|
||||
|
||||
// Get Modbus Master send destination address.
|
||||
UCHAR ucMBMasterGetDestAddress( void )
|
||||
{
|
||||
return ucMBMasterDestAddress;
|
||||
return atomic_load(&ucMBMasterDestAddress);
|
||||
}
|
||||
|
||||
// Set Modbus Master send destination address.
|
||||
void vMBMasterSetDestAddress( UCHAR Address )
|
||||
{
|
||||
ucMBMasterDestAddress = Address;
|
||||
atomic_store(&(ucMBMasterDestAddress), Address);
|
||||
}
|
||||
|
||||
// Get Modbus Master current error event type.
|
||||
eMBMasterErrorEventType inline eMBMasterGetErrorType( void )
|
||||
{
|
||||
return eMBMasterCurErrorType;
|
||||
return atomic_load(&eMBMasterCurErrorType);
|
||||
}
|
||||
|
||||
// Set Modbus Master current error event type.
|
||||
void IRAM_ATTR vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
|
||||
{
|
||||
eMBMasterCurErrorType = errorType;
|
||||
atomic_store(&(eMBMasterCurErrorType), errorType);
|
||||
}
|
||||
|
||||
/* Get Modbus Master send PDU's buffer address pointer.*/
|
||||
void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame )
|
||||
{
|
||||
*pucFrame = ( UCHAR * ) &ucMasterSndBuf[MB_SER_PDU_PDU_OFF];
|
||||
*pucFrame = ( UCHAR * ) &ucMasterSndBuf[MB_SEND_BUF_PDU_OFF];
|
||||
}
|
||||
|
||||
/* Set Modbus Master send PDU's buffer length.*/
|
||||
void vMBMasterSetPDUSndLength( USHORT SendPDULength )
|
||||
{
|
||||
usMasterSendPDULength = SendPDULength;
|
||||
atomic_store(&(usMasterSendPDULength), SendPDULength);
|
||||
}
|
||||
|
||||
/* Get Modbus Master send PDU's buffer length.*/
|
||||
USHORT usMBMasterGetPDUSndLength( void )
|
||||
{
|
||||
return usMasterSendPDULength;
|
||||
return atomic_load(&usMasterSendPDULength);
|
||||
}
|
||||
|
||||
/* Set Modbus Master current timer mode.*/
|
||||
void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode )
|
||||
{
|
||||
eMasterCurTimerMode = eMBTimerMode;
|
||||
atomic_store(&(eMasterCurTimerMode), eMBTimerMode);
|
||||
}
|
||||
|
||||
/* Get Modbus Master current timer mode.*/
|
||||
eMBMasterTimerMode MB_PORT_ISR_ATTR xMBMasterGetCurTimerMode( void )
|
||||
{
|
||||
return eMasterCurTimerMode;
|
||||
return atomic_load(&eMasterCurTimerMode);
|
||||
}
|
||||
|
||||
/* The master request is broadcast? */
|
||||
@ -542,8 +560,15 @@ BOOL MB_PORT_ISR_ATTR xMBMasterRequestIsBroadcast( void )
|
||||
}
|
||||
|
||||
/* The master request is broadcast? */
|
||||
void vMBMasterRequestSetType( BOOL xIsBroadcast ){
|
||||
xFrameIsBroadcast = xIsBroadcast;
|
||||
void vMBMasterRequestSetType( BOOL xIsBroadcast )
|
||||
{
|
||||
atomic_store(&(xFrameIsBroadcast), xIsBroadcast);
|
||||
}
|
||||
|
||||
// Get Modbus Master communication mode.
|
||||
eMBMode ucMBMasterGetCommMode(void)
|
||||
{
|
||||
return eMBMasterCurrentMode;
|
||||
}
|
||||
|
||||
#endif // MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
|
||||
|
@ -158,7 +158,7 @@ eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||
UCHAR *pucMBRTUFrame = ( UCHAR* ) ucRTUBuf;
|
||||
USHORT usFrameLength = usRcvBufferPos;
|
||||
|
||||
if( xMBSerialPortGetRequest( &pucMBRTUFrame, &usFrameLength ) == FALSE )
|
||||
if( xMBPortSerialGetRequest( &pucMBRTUFrame, &usFrameLength ) == FALSE )
|
||||
{
|
||||
return MB_EIO;
|
||||
}
|
||||
@ -222,7 +222,7 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
eSndState = STATE_TX_XMIT;
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
if( xMBSerialPortSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE )
|
||||
if( xMBPortSerialSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ eMBMasterRTUStart( void )
|
||||
* to STATE_M_RX_IDLE. This makes sure that we delay startup of the
|
||||
* modbus protocol stack until the bus is free.
|
||||
*/
|
||||
eRcvState = STATE_M_RX_IDLE; //STATE_M_RX_INIT (We start processing immediately)
|
||||
eRcvState = STATE_M_RX_INIT;
|
||||
vMBMasterPortSerialEnable( TRUE, FALSE );
|
||||
vMBMasterPortTimersT35Enable( );
|
||||
|
||||
@ -164,7 +164,7 @@ eMBMasterRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLengt
|
||||
UCHAR *pucMBRTUFrame = ( UCHAR* ) ucMasterRTURcvBuf;
|
||||
USHORT usFrameLength = usMasterRcvBufferPos;
|
||||
|
||||
if( xMBMasterSerialPortGetResponse( &pucMBRTUFrame, &usFrameLength ) == FALSE )
|
||||
if( xMBMasterPortSerialGetResponse( &pucMBRTUFrame, &usFrameLength ) == FALSE )
|
||||
{
|
||||
return MB_EIO;
|
||||
}
|
||||
@ -230,12 +230,12 @@ eMBMasterRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength
|
||||
|
||||
/* Activate the transmitter. */
|
||||
eSndState = STATE_M_TX_XMIT;
|
||||
|
||||
if ( xMBMasterSerialPortSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE )
|
||||
|
||||
if ( xMBMasterPortSerialSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
|
||||
|
||||
// The place to enable RS485 driver
|
||||
vMBMasterPortSerialEnable( FALSE, TRUE );
|
||||
}
|
||||
@ -252,7 +252,9 @@ xMBMasterRTUReceiveFSM( void )
|
||||
BOOL xStatus = FALSE;
|
||||
UCHAR ucByte;
|
||||
|
||||
assert(( eSndState == STATE_M_TX_IDLE ) || ( eSndState == STATE_M_TX_XFWR ));
|
||||
if ( ( eSndState != STATE_M_TX_IDLE ) && ( eSndState != STATE_M_TX_XFWR ) ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Always read the character. */
|
||||
xStatus = xMBMasterPortSerialGetByte( ( CHAR * ) & ucByte );
|
||||
@ -264,6 +266,7 @@ xMBMasterRTUReceiveFSM( void )
|
||||
*/
|
||||
case STATE_M_RX_INIT:
|
||||
vMBMasterPortTimersT35Enable( );
|
||||
ESP_LOGD("DBG", "Start initialization phase.");
|
||||
break;
|
||||
|
||||
/* In the error state we wait until all characters in the
|
||||
@ -283,12 +286,12 @@ xMBMasterRTUReceiveFSM( void )
|
||||
* Disable timer of respond timeout and change the transmiter state to idle.
|
||||
*/
|
||||
vMBMasterPortTimersDisable( );
|
||||
eSndState = STATE_M_TX_IDLE;
|
||||
|
||||
usMasterRcvBufferPos = 0;
|
||||
if( xStatus && ucByte ) {
|
||||
ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte;
|
||||
eRcvState = STATE_M_RX_RCV;
|
||||
eSndState = STATE_M_TX_IDLE;
|
||||
}
|
||||
|
||||
/* Enable t3.5 timers. */
|
||||
@ -327,7 +330,9 @@ xMBMasterRTUTransmitFSM( void )
|
||||
BOOL xNeedPoll = TRUE;
|
||||
BOOL xFrameIsBroadcast = FALSE;
|
||||
|
||||
assert( eRcvState == STATE_M_RX_IDLE );
|
||||
if ( eRcvState != STATE_M_RX_IDLE ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch ( eSndState )
|
||||
{
|
||||
@ -350,7 +355,8 @@ xMBMasterRTUTransmitFSM( void )
|
||||
}
|
||||
else
|
||||
{
|
||||
xFrameIsBroadcast = ( ucMasterRTUSndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
|
||||
xFrameIsBroadcast = ( ucMasterRTUSndBuf[MB_SEND_BUF_PDU_OFF - MB_SER_PDU_PDU_OFF]
|
||||
== MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
|
||||
vMBMasterRequestSetType( xFrameIsBroadcast );
|
||||
eSndState = STATE_M_TX_XFWR;
|
||||
/* If the frame is broadcast ,master will enable timer of convert delay,
|
||||
@ -380,6 +386,7 @@ xMBMasterRTUTimerExpired(void)
|
||||
/* Timer t35 expired. Startup phase is finished. */
|
||||
case STATE_M_RX_INIT:
|
||||
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_READY);
|
||||
ESP_EARLY_LOGD("DBG", "RTU timer, init FSM state.");
|
||||
break;
|
||||
|
||||
/* A frame was received and t35 expired. Notify the listener that
|
||||
|
@ -124,10 +124,14 @@ eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLength )
|
||||
*pusLength = usLength - MB_TCP_FUNC;
|
||||
eStatus = MB_ENOERR;
|
||||
|
||||
/* Modbus TCP does not use any addresses. Fake the source address such
|
||||
* that the processing part deals with this frame.
|
||||
/* The regular Modbus TCP does not use any addresses. Fake the MBAP UID in this case.
|
||||
* The MBAP UID field support is used for RTU over TCP option if enabled.
|
||||
*/
|
||||
#if MB_TCP_UID_ENABLED
|
||||
*pucRcvAddress = pucMBTCPFrame[MB_TCP_UID];
|
||||
#else
|
||||
*pucRcvAddress = MB_TCP_PSEUDO_ADDRESS;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -152,6 +156,7 @@ eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength )
|
||||
*/
|
||||
pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U;
|
||||
pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF;
|
||||
|
||||
if( xMBTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
|
@ -123,10 +123,14 @@ eMBMasterTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLeng
|
||||
*pusLength = usLength - MB_TCP_FUNC;
|
||||
eStatus = MB_ENOERR;
|
||||
|
||||
/* Modbus TCP does not use any addresses. Fake the source address such
|
||||
* that the processing part deals with this frame.
|
||||
/* Get MBAP UID field if its support is enabled.
|
||||
* Otherwise just ignore this field.
|
||||
*/
|
||||
#if MB_TCP_UID_ENABLED
|
||||
*pucRcvAddress = pucMBTCPFrame[MB_TCP_UID];
|
||||
#else
|
||||
*pucRcvAddress = MB_TCP_PSEUDO_ADDRESS;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -137,20 +141,27 @@ eMBMasterTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLeng
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength )
|
||||
eMBMasterTCPSend( UCHAR ucAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
UCHAR *pucMBTCPFrame = ( UCHAR * ) pucFrame - MB_TCP_FUNC;
|
||||
USHORT usTCPLength = usLength + MB_TCP_FUNC;
|
||||
|
||||
/* The MBAP header is already initialized because the caller calls this
|
||||
* function with the buffer returned by the previous call. Therefore we
|
||||
* only have to update the length in the header. Note that the length
|
||||
* header includes the size of the Modbus PDU and the UID Byte. Therefore
|
||||
* the length is usLength plus one.
|
||||
/* Note that the length in the MBAP header includes the size of the Modbus PDU
|
||||
* and the UID Byte. Therefore the length is usLength plus one.
|
||||
*/
|
||||
pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U;
|
||||
pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF;
|
||||
|
||||
/* Set UID field in the MBAP if it is supported.
|
||||
* If the RTU over TCP is not supported, the UID = 0 or 0xFF.
|
||||
*/
|
||||
#if MB_TCP_UID_ENABLED
|
||||
pucMBTCPFrame[MB_TCP_UID] = ucAddress;
|
||||
#else
|
||||
pucMBTCPFrame[MB_TCP_UID] = 0x00;
|
||||
#endif
|
||||
|
||||
if( xMBMasterTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
|
@ -50,7 +50,7 @@ void eMBMasterTCPStart( void );
|
||||
void eMBMasterTCPStop( void );
|
||||
eMBErrorCode eMBMasterTCPReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
|
||||
USHORT * pusLength );
|
||||
eMBErrorCode eMBMasterTCPSend( UCHAR _unused, const UCHAR * pucFrame,
|
||||
eMBErrorCode eMBMasterTCPSend( UCHAR ucAddress, const UCHAR * pucFrame,
|
||||
USHORT usLength );
|
||||
BOOL xMBMasterTCPTimerExpired(void);
|
||||
|
||||
|
@ -73,13 +73,61 @@ vMBPortSetMode( UCHAR ucMode )
|
||||
EXIT_CRITICAL_SECTION();
|
||||
}
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_SLAVE_RTU_ENABLED || MB_SLAVE_ASCII_ENABLED
|
||||
|
||||
BOOL xMBPortSerialWaitEvent(QueueHandle_t xMbUartQueue, uart_event_t* pxEvent, ULONG xTimeout)
|
||||
{
|
||||
BOOL xResult = (BaseType_t)xQueueReceive(xMbUartQueue, (void*)pxEvent, (TickType_t) xTimeout);
|
||||
ESP_LOGD(__func__, "UART event: %d ", pxEvent->type);
|
||||
ESP_LOGD(MB_PORT_TAG, "%s, UART event: %u ", __func__, (unsigned)pxEvent->type);
|
||||
return xResult;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED
|
||||
|
||||
/*
|
||||
* The function is called from ASCII/RTU module to get processed data buffer. Sets the
|
||||
* received buffer and its length using parameters.
|
||||
*/
|
||||
__attribute__ ((weak))
|
||||
BOOL xMBMasterPortSerialGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength )
|
||||
{
|
||||
ESP_LOGD(MB_PORT_TAG, " %s default", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function is called from ASCII/RTU module to set processed data buffer
|
||||
* to be sent in transmitter state machine.
|
||||
*/
|
||||
__attribute__ ((weak))
|
||||
BOOL xMBMasterPortSerialSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength )
|
||||
{
|
||||
ESP_LOGD(MB_PORT_TAG, "%s default", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MB_SLAVE_RTU_ENABLED || MB_SLAVE_ASCII_ENABLED
|
||||
|
||||
__attribute__ ((weak))
|
||||
BOOL xMBPortSerialGetRequest( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength )
|
||||
{
|
||||
ESP_LOGD(MB_PORT_TAG, "%s default", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
__attribute__ ((weak))
|
||||
BOOL xMBPortSerialSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength )
|
||||
{
|
||||
ESP_LOGD(MB_PORT_TAG, "%s default", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MB_TCP_DEBUG
|
||||
|
||||
// This function is kept to realize legacy freemodbus frame logging functionality
|
||||
|
@ -91,6 +91,10 @@
|
||||
#define MB_TCP_SEND_TIMEOUT (pdMS_TO_TICKS(MB_TCP_SEND_TIMEOUT_MS))
|
||||
#define MB_TCP_PORT_MAX_CONN (CONFIG_FMB_TCP_PORT_MAX_CONN)
|
||||
|
||||
// Set the API unlock time to maximum response time
|
||||
// The actual release time will be dependent on the timer time
|
||||
#define MB_MAX_RESPONSE_TIME_MS (5000)
|
||||
|
||||
#define MB_TCP_FRAME_LOG_BUFSIZE (256)
|
||||
|
||||
#define MB_PORT_HAS_CLOSE (1) // Define to explicitly close port on destroy
|
||||
|
@ -44,14 +44,11 @@
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
#include "port.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "mbconfig.h"
|
||||
#include "port_serial_slave.h"
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static QueueHandle_t xQueueHdl;
|
||||
|
||||
#define MB_EVENT_QUEUE_SIZE (6)
|
||||
#define MB_EVENT_QUEUE_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_EVENT_QUEUE_TIMEOUT))
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL
|
||||
xMBPortEventInit( void )
|
||||
@ -89,7 +86,7 @@ xMBPortEventPost( eMBEventType eEvent )
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
if (xStatus != pdTRUE) {
|
||||
ESP_EARLY_LOGV(MB_PORT_TAG, "%s: Post message failure = %d.", __func__, xStatus);
|
||||
ESP_EARLY_LOGV(MB_PORT_TAG, "%s: Post message failure = %u.", __func__, (unsigned)xStatus);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -35,27 +35,24 @@
|
||||
*/
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb_m.h"
|
||||
#include "mbport.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "mb_m.h"
|
||||
#include "mbport.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
#include "port.h"
|
||||
#include "mbport.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "port_serial_master.h"
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
// Event bit mask for xMBMasterPortEventGet()
|
||||
#define MB_EVENT_POLL_MASK (EventBits_t)( EV_MASTER_READY | \
|
||||
EV_MASTER_FRAME_RECEIVED | \
|
||||
EV_MASTER_EXECUTE | \
|
||||
EV_MASTER_FRAME_SENT | \
|
||||
EV_MASTER_FRAME_TRANSMIT | \
|
||||
EV_MASTER_ERROR_PROCESS )
|
||||
|
||||
// Event bit mask for eMBMasterWaitRequestFinish()
|
||||
#define MB_EVENT_REQ_MASK (EventBits_t)( EV_MASTER_PROCESS_SUCCESS | \
|
||||
@ -63,12 +60,13 @@
|
||||
EV_MASTER_ERROR_RECEIVE_DATA | \
|
||||
EV_MASTER_ERROR_EXECUTE_FUNCTION )
|
||||
|
||||
#define MB_EVENT_RESOURCE (EventBits_t)( 0x0080 )
|
||||
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static EventGroupHandle_t xResourceMasterHdl;
|
||||
static SemaphoreHandle_t xResourceMasterHdl;
|
||||
static EventGroupHandle_t xEventGroupMasterHdl;
|
||||
static EventGroupHandle_t xEventGroupMasterConfirmHdl;
|
||||
static QueueHandle_t xQueueMasterHdl;
|
||||
|
||||
static uint64_t xTransactionID = 0;
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
|
||||
@ -79,45 +77,60 @@ xMBMasterPortEventInit( void )
|
||||
xEventGroupMasterConfirmHdl = xEventGroupCreate();
|
||||
MB_PORT_CHECK((xEventGroupMasterHdl != NULL) && (xEventGroupMasterConfirmHdl != NULL),
|
||||
FALSE, "mb stack event group creation error.");
|
||||
xQueueMasterHdl = xQueueCreate(MB_EVENT_QUEUE_SIZE, sizeof(xMBMasterEventType));
|
||||
MB_PORT_CHECK(xQueueMasterHdl, FALSE, "mb stack event group creation error.");
|
||||
vQueueAddToRegistry(xQueueMasterHdl, "MbMasterPortEventQueue");
|
||||
xTransactionID = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL MB_PORT_ISR_ATTR
|
||||
xMBMasterPortEventPost( eMBMasterEventType eEvent )
|
||||
xMBMasterPortEventPost( eMBMasterEventEnum eEvent)
|
||||
{
|
||||
BOOL bStatus = FALSE;
|
||||
eMBMasterEventType eTempEvent = eEvent;
|
||||
BaseType_t xStatus, xHigherPriorityTaskWoken = pdFALSE;
|
||||
assert(xQueueMasterHdl != NULL);
|
||||
xMBMasterEventType xEvent;
|
||||
xEvent.xPostTimestamp = esp_timer_get_time();
|
||||
|
||||
if (eEvent & EV_MASTER_TRANS_START) {
|
||||
atomic_store(&(xTransactionID), xEvent.xPostTimestamp);
|
||||
}
|
||||
xEvent.eEvent = (eEvent & ~EV_MASTER_TRANS_START);
|
||||
|
||||
if( (BOOL)xPortInIsrContext() == TRUE )
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
BaseType_t xResult = xEventGroupSetBitsFromISR( xEventGroupMasterHdl,
|
||||
(EventBits_t) eTempEvent,
|
||||
&xHigherPriorityTaskWoken );
|
||||
// Was the message posted successfully?
|
||||
if( xResult == pdPASS ) {
|
||||
// If xHigherPriorityTaskWoken is now set to pdTRUE
|
||||
// then a context switch should be requested.
|
||||
if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR();
|
||||
bStatus = TRUE;
|
||||
} else {
|
||||
bStatus = FALSE;
|
||||
if( (BOOL)xPortInIsrContext() == TRUE ) {
|
||||
xStatus = xQueueSendFromISR(xQueueMasterHdl, (const void*)&xEvent, &xHigherPriorityTaskWoken);
|
||||
if ( xHigherPriorityTaskWoken ) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
if (xStatus != pdTRUE) {
|
||||
ESP_EARLY_LOGV(MB_PORT_TAG, "%s: Post message failure = %d.", __func__, xStatus);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
xStatus = xQueueSend(xQueueMasterHdl, (const void*)&xEvent, MB_EVENT_QUEUE_TIMEOUT);
|
||||
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "%s: Post message failure.", __func__);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set event bits if the function is called from task
|
||||
// The return result is not checked here because
|
||||
// It might be that event bit was cleared automatically as a
|
||||
// task that was waiting for the bit was removed from the Blocked state.
|
||||
(void) xEventGroupSetBits( xEventGroupMasterHdl, (EventBits_t)eTempEvent );
|
||||
bStatus = TRUE;
|
||||
}
|
||||
return bStatus;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
eMBMasterEventType
|
||||
xMBMasterPortFsmWaitConfirmation( eMBMasterEventType eEventMask, ULONG ulTimeout)
|
||||
BOOL
|
||||
xMBMasterPortEventGet(xMBMasterEventType *peEvent)
|
||||
{
|
||||
assert(xQueueMasterHdl != NULL);
|
||||
BOOL xEventHappened = FALSE;
|
||||
|
||||
if (xQueueReceive(xQueueMasterHdl, peEvent, portMAX_DELAY) == pdTRUE) {
|
||||
peEvent->xTransactionId = atomic_load(&xTransactionID);
|
||||
// Set event bits in confirmation group (for synchronization with port task)
|
||||
xEventGroupSetBits(xEventGroupMasterConfirmHdl, peEvent->eEvent);
|
||||
peEvent->xGetTimestamp = esp_timer_get_time();
|
||||
xEventHappened = TRUE;
|
||||
}
|
||||
return xEventHappened;
|
||||
}
|
||||
|
||||
eMBMasterEventEnum
|
||||
xMBMasterPortFsmWaitConfirmation( eMBMasterEventEnum eEventMask, ULONG ulTimeout)
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
uxBits = xEventGroupWaitBits( xEventGroupMasterConfirmHdl, // The event group being tested.
|
||||
@ -129,39 +142,19 @@ xMBMasterPortFsmWaitConfirmation( eMBMasterEventType eEventMask, ULONG ulTimeout
|
||||
// Clear confirmation events that where set in the mask
|
||||
xEventGroupClearBits( xEventGroupMasterConfirmHdl, (uxBits & eEventMask) );
|
||||
}
|
||||
return (eMBMasterEventType)(uxBits & eEventMask);
|
||||
return (eMBMasterEventEnum)(uxBits & eEventMask);
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterPortEventGet( eMBMasterEventType* eEvent )
|
||||
uint64_t xMBMasterPortGetTransactionId( )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
BOOL xEventHappened = FALSE;
|
||||
uxBits = xEventGroupWaitBits( xEventGroupMasterHdl, // The event group being tested.
|
||||
MB_EVENT_POLL_MASK, // The bits within the event group to wait for.
|
||||
pdTRUE, // Masked bits should be cleared before returning.
|
||||
pdFALSE, // Don't wait for both bits, either bit will do.
|
||||
portMAX_DELAY); // Wait forever for either bit to be set.
|
||||
// Check if poll event is correct
|
||||
if (MB_PORT_CHECK_EVENT(uxBits, MB_EVENT_POLL_MASK)) {
|
||||
*eEvent = (eMBMasterEventType)(uxBits & MB_EVENT_POLL_MASK);
|
||||
// Set event bits in confirmation group (for synchronization with port task)
|
||||
xEventGroupSetBits( xEventGroupMasterConfirmHdl, *eEvent );
|
||||
xEventHappened = TRUE;
|
||||
} else {
|
||||
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event triggered = %d.", __func__, uxBits);
|
||||
*eEvent = (eMBMasterEventType)uxBits;
|
||||
xEventHappened = FALSE;
|
||||
}
|
||||
return xEventHappened;
|
||||
return atomic_load(&xTransactionID);
|
||||
}
|
||||
|
||||
// This function is initialize the OS resource for modbus master.
|
||||
void vMBMasterOsResInit( void )
|
||||
{
|
||||
xResourceMasterHdl = xEventGroupCreate();
|
||||
xEventGroupSetBits(xResourceMasterHdl, MB_EVENT_RESOURCE);
|
||||
MB_PORT_CHECK((xResourceMasterHdl != NULL), ; , "Resource create error.");
|
||||
xResourceMasterHdl = xSemaphoreCreateBinary();
|
||||
MB_PORT_CHECK((xResourceMasterHdl != NULL), ; , "%s: Resource create error.", __func__);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,26 +167,24 @@ void vMBMasterOsResInit( void )
|
||||
*/
|
||||
BOOL xMBMasterRunResTake( LONG lTimeOut )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
uxBits = xEventGroupWaitBits( xResourceMasterHdl, // The event group being tested.
|
||||
MB_EVENT_RESOURCE, // The bits within the event group to wait for.
|
||||
pdTRUE, // Masked bits should be cleared before returning.
|
||||
pdFALSE, // Don't wait for both bits, either bit will do.
|
||||
lTimeOut); // Resource wait timeout.
|
||||
MB_PORT_CHECK((uxBits == MB_EVENT_RESOURCE), FALSE , "Take resource failure.");
|
||||
ESP_LOGD(MB_PORT_TAG,"%s:Take resource (%x) (%lu ticks).", __func__, uxBits, lTimeOut);
|
||||
BaseType_t xStatus = pdTRUE;
|
||||
xStatus = xSemaphoreTake( xResourceMasterHdl, lTimeOut );
|
||||
MB_PORT_CHECK((xStatus == pdTRUE), FALSE , "%s: Resource take failure.", __func__);
|
||||
ESP_LOGD(MB_PORT_TAG,"%s:Take MB resource (%lu ticks).", __func__, lTimeOut);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is release Modbus Master running resource.
|
||||
* Note:The resource is define by Operating System.If you not use OS this function can be empty.
|
||||
* Note:The resource is define by Operating System. If you not use OS this function can be empty.
|
||||
*/
|
||||
void vMBMasterRunResRelease( void )
|
||||
{
|
||||
EventBits_t uxBits = xEventGroupSetBits( xResourceMasterHdl, MB_EVENT_RESOURCE );
|
||||
MB_PORT_CHECK((uxBits == MB_EVENT_RESOURCE), ; , "Resource release failure.");
|
||||
ESP_LOGD(MB_PORT_TAG,"%s: Release resource (%x).", __func__, uxBits);
|
||||
BaseType_t xStatus = pdFALSE;
|
||||
xStatus = xSemaphoreGive( xResourceMasterHdl );
|
||||
if (xStatus != pdTRUE) {
|
||||
ESP_LOGD(MB_PORT_TAG,"%s: Release resource fail.", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,8 +198,7 @@ void vMBMasterRunResRelease( void )
|
||||
*/
|
||||
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
|
||||
{
|
||||
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RESPOND_TIMEOUT);
|
||||
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RESPOND_TIMEOUT' failed!", __func__);
|
||||
(void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_RESPOND_TIMEOUT );
|
||||
ESP_LOGD(MB_PORT_TAG,"%s:Callback respond timeout.", __func__);
|
||||
}
|
||||
|
||||
@ -222,10 +212,9 @@ void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData
|
||||
*/
|
||||
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
|
||||
{
|
||||
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RECEIVE_DATA);
|
||||
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RECEIVE_DATA' failed!", __func__);
|
||||
(void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_RECEIVE_DATA );
|
||||
ESP_LOGD(MB_PORT_TAG,"%s:Callback receive data timeout failure.", __func__);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("Err rcv buf", (void*)pucPDUData, (uint16_t)ucPDULength, ESP_LOG_DEBUG);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("Err rcv buf", (void *)pucPDUData, (USHORT)ucPDULength, ESP_LOG_DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -240,10 +229,9 @@ void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, U
|
||||
*/
|
||||
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
|
||||
{
|
||||
BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION);
|
||||
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_EXECUTE_FUNCTION' failed!", __func__);
|
||||
xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_EXECUTE_FUNCTION );
|
||||
ESP_LOGD(MB_PORT_TAG,"%s:Callback execute data handler failure.", __func__);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("Exec func buf", (void*)pucPDUData, (uint16_t)ucPDULength, ESP_LOG_DEBUG);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("Exec func buf", (void*)pucPDUData, (USHORT)ucPDULength, ESP_LOG_DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -251,13 +239,9 @@ void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUDat
|
||||
* @note There functions will block modbus master poll while execute OS waiting.
|
||||
* So,for real-time of system. Do not execute too much waiting process.
|
||||
*/
|
||||
void vMBMasterCBRequestSuccess( void ) {
|
||||
/**
|
||||
* @note This code is use OS's event mechanism for modbus master protocol stack.
|
||||
* If you don't use OS, you can change it.
|
||||
*/
|
||||
BOOL ret = xMBMasterPortEventPost(EV_MASTER_PROCESS_SUCCESS);
|
||||
MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_PROCESS_SUCCESS' failed!", __func__);
|
||||
void vMBMasterCBRequestSuccess( void )
|
||||
{
|
||||
(void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_PROCESS_SUCCESS );
|
||||
ESP_LOGD(MB_PORT_TAG,"%s: Callback request success.", __func__);
|
||||
}
|
||||
|
||||
@ -272,19 +256,19 @@ void vMBMasterCBRequestSuccess( void ) {
|
||||
*/
|
||||
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
eMBMasterEventType xRecvedEvent;
|
||||
eMBMasterEventEnum xRecvedEvent;
|
||||
|
||||
EventBits_t uxBits = xEventGroupWaitBits( xEventGroupMasterHdl, // The event group being tested.
|
||||
MB_EVENT_REQ_MASK, // The bits within the event group to wait for.
|
||||
pdTRUE, // Masked bits should be cleared before returning.
|
||||
pdFALSE, // Don't wait for both bits, either bit will do.
|
||||
portMAX_DELAY ); // Wait forever for either bit to be set.
|
||||
xRecvedEvent = (eMBMasterEventType)(uxBits);
|
||||
xRecvedEvent = (eMBMasterEventEnum)(uxBits);
|
||||
if (xRecvedEvent) {
|
||||
ESP_LOGD(MB_PORT_TAG,"%s: returned event = 0x%x", __func__, xRecvedEvent);
|
||||
ESP_LOGD(MB_PORT_TAG,"%s: returned event = 0x%x", __func__, (int)xRecvedEvent);
|
||||
if (!(xRecvedEvent & MB_EVENT_REQ_MASK)) {
|
||||
// if we wait for certain event bits but get from poll subset
|
||||
ESP_LOGE(MB_PORT_TAG,"%s: incorrect event set = 0x%x", __func__, xRecvedEvent);
|
||||
ESP_LOGE(MB_PORT_TAG,"%s: incorrect event set = 0x%x", __func__, (int)xRecvedEvent);
|
||||
}
|
||||
xEventGroupSetBits( xEventGroupMasterConfirmHdl, (xRecvedEvent & MB_EVENT_REQ_MASK) );
|
||||
if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_PROCESS_SUCCESS)) {
|
||||
@ -297,7 +281,7 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
|
||||
eErrStatus = MB_MRE_EXE_FUN;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, uxBits);
|
||||
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, (int)uxBits);
|
||||
// https://github.com/espressif/esp-idf/issues/5275
|
||||
// if a no event is received, that means vMBMasterPortEventClose()
|
||||
// has been closed, so event group has been deleted by FreeRTOS, which
|
||||
@ -310,9 +294,22 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
|
||||
|
||||
void vMBMasterPortEventClose(void)
|
||||
{
|
||||
vEventGroupDelete(xEventGroupMasterHdl);
|
||||
vEventGroupDelete(xEventGroupMasterConfirmHdl);
|
||||
vEventGroupDelete(xResourceMasterHdl);
|
||||
if (xEventGroupMasterHdl) {
|
||||
vEventGroupDelete(xEventGroupMasterHdl);
|
||||
xEventGroupMasterHdl = NULL;
|
||||
}
|
||||
if (xQueueMasterHdl) {
|
||||
vQueueDelete(xQueueMasterHdl);
|
||||
xQueueMasterHdl = NULL;
|
||||
}
|
||||
if (xEventGroupMasterConfirmHdl) {
|
||||
vEventGroupDelete(xEventGroupMasterConfirmHdl);
|
||||
xEventGroupMasterConfirmHdl = NULL;
|
||||
}
|
||||
if (xResourceMasterHdl) {
|
||||
vSemaphoreDelete(xResourceMasterHdl);
|
||||
xResourceMasterHdl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -96,7 +96,7 @@ static USHORT usMBPortSerialRxPoll(size_t xEventSize)
|
||||
#if !CONFIG_FMB_TIMER_PORT_ENABLED
|
||||
pxMBPortCBTimerExpired();
|
||||
#endif
|
||||
ESP_LOGD(TAG, "RX: %d bytes\n", usCnt);
|
||||
ESP_LOGD(TAG, "RX: %u bytes\n", (unsigned)usCnt);
|
||||
}
|
||||
return usCnt;
|
||||
}
|
||||
@ -112,7 +112,7 @@ BOOL xMBPortSerialTxPoll(void)
|
||||
// Calls the modbus stack callback function to let it fill the UART transmit buffer.
|
||||
bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // callback to transmit FSM
|
||||
}
|
||||
ESP_LOGD(TAG, "MB_TX_buffer send: (%d) bytes\n", (uint16_t)usCount);
|
||||
ESP_LOGD(TAG, "MB_TX_buffer send: (%u) bytes\n", (unsigned)usCount);
|
||||
// Waits while UART sending the packet
|
||||
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
|
||||
vMBPortSerialEnable(TRUE, FALSE);
|
||||
@ -128,11 +128,11 @@ static void vUartTask(void *pvParameters)
|
||||
USHORT usResult = 0;
|
||||
for(;;) {
|
||||
if (xMBPortSerialWaitEvent(xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) {
|
||||
ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber);
|
||||
ESP_LOGD(TAG, "MB_uart[%u] event:", (unsigned)ucUartNumber);
|
||||
switch(xEvent.type) {
|
||||
//Event of UART receving data
|
||||
case UART_DATA:
|
||||
ESP_LOGD(TAG,"Data event, length: %d", xEvent.size);
|
||||
ESP_LOGD(TAG,"Data event, length: %u", (unsigned)xEvent.size);
|
||||
// This flag set in the event means that no more
|
||||
// data received during configured timeout and UART TOUT feature is triggered
|
||||
if (xEvent.timeout_flag) {
|
||||
@ -140,34 +140,34 @@ static void vUartTask(void *pvParameters)
|
||||
ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size));
|
||||
// Read received data and send it to modbus stack
|
||||
usResult = usMBPortSerialRxPoll(xEvent.size);
|
||||
ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult);
|
||||
ESP_LOGD(TAG,"Timeout occured, processed: %u bytes", (unsigned)usResult);
|
||||
}
|
||||
break;
|
||||
//Event of HW FIFO overflow detected
|
||||
case UART_FIFO_OVF:
|
||||
ESP_LOGD(TAG, "hw fifo overflow\n");
|
||||
ESP_LOGD(TAG, "hw fifo overflow");
|
||||
xQueueReset(xMbUartQueue);
|
||||
break;
|
||||
//Event of UART ring buffer full
|
||||
case UART_BUFFER_FULL:
|
||||
ESP_LOGD(TAG, "ring buffer full\n");
|
||||
ESP_LOGD(TAG, "ring buffer full");
|
||||
xQueueReset(xMbUartQueue);
|
||||
uart_flush_input(ucUartNumber);
|
||||
break;
|
||||
//Event of UART RX break detected
|
||||
case UART_BREAK:
|
||||
ESP_LOGD(TAG, "uart rx break\n");
|
||||
ESP_LOGD(TAG, "uart rx break");
|
||||
break;
|
||||
//Event of UART parity check error
|
||||
case UART_PARITY_ERR:
|
||||
ESP_LOGD(TAG, "uart parity error\n");
|
||||
ESP_LOGD(TAG, "uart parity error");
|
||||
break;
|
||||
//Event of UART frame error
|
||||
case UART_FRAME_ERR:
|
||||
ESP_LOGD(TAG, "uart frame error\n");
|
||||
ESP_LOGD(TAG, "uart frame error");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(TAG, "uart event type: %d\n", xEvent.type);
|
||||
ESP_LOGD(TAG, "uart event type: %u", (unsigned)xEvent.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -195,7 +195,7 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate,
|
||||
ucParity = UART_PARITY_EVEN;
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Incorrect parity option: %d", eParity);
|
||||
ESP_LOGE(TAG, "Incorrect parity option: %u", (unsigned)eParity);
|
||||
return FALSE;
|
||||
}
|
||||
switch(ucDataBits){
|
||||
@ -222,22 +222,26 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 2,
|
||||
.source_clk = UART_SCLK_APB
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0))
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
#else
|
||||
.source_clk = UART_SCLK_APB,
|
||||
#endif
|
||||
};
|
||||
// Set UART config
|
||||
xErr = uart_param_config(ucUartNumber, &xUartConfig);
|
||||
MB_PORT_CHECK((xErr == ESP_OK),
|
||||
FALSE, "mb config failure, uart_param_config() returned (0x%x).", xErr);
|
||||
FALSE, "mb config failure, uart_param_config() returned (0x%x).", (int)xErr);
|
||||
// Install UART driver, and get the queue.
|
||||
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
|
||||
MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
|
||||
"mb serial driver failure, uart_driver_install() returned (0x%x).", xErr);
|
||||
"mb serial driver failure, uart_driver_install() returned (0x%x).", (int)xErr);
|
||||
#if !CONFIG_FMB_TIMER_PORT_ENABLED
|
||||
// Set timeout for TOUT interrupt (T3.5 modbus time)
|
||||
xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
|
||||
"mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr);
|
||||
"mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", (int)xErr);
|
||||
#endif
|
||||
|
||||
// Set always timeout flag to trigger timeout interrupt even after rx fifo full
|
||||
@ -253,24 +257,13 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate,
|
||||
// Force exit from function with failure
|
||||
MB_PORT_CHECK(FALSE, FALSE,
|
||||
"mb stack serial task creation error. xTaskCreate() returned (0x%x).",
|
||||
xStatus);
|
||||
(int)xStatus);
|
||||
} else {
|
||||
vTaskSuspend(xMbTaskHandle); // Suspend serial task while stack is not started
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xMBSerialPortGetRequest( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength )
|
||||
{
|
||||
BOOL eStatus = TRUE;
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
BOOL xMBSerialPortSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBPortSerialClose(void)
|
||||
{
|
||||
(void)vTaskSuspend(xMbTaskHandle);
|
||||
|
@ -52,6 +52,9 @@
|
||||
#include "port_serial_master.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_SERIAL_RX_SEMA_TOUT_MS (1000)
|
||||
#define MB_SERIAL_RX_SEMA_TOUT (pdMS_TO_TICKS(MB_SERIAL_RX_SEMA_TOUT_MS))
|
||||
#define MB_SERIAL_RX_FLUSH_RETRY (2)
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static const CHAR *TAG = "MB_MASTER_SERIAL";
|
||||
@ -66,16 +69,75 @@ static UCHAR ucUartNumber = UART_NUM_MAX - 1;
|
||||
static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag
|
||||
static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag
|
||||
|
||||
static SemaphoreHandle_t xMasterSemaRxHandle; // Rx blocking semaphore handle
|
||||
|
||||
static BOOL xMBMasterPortRxSemaInit( void )
|
||||
{
|
||||
xMasterSemaRxHandle = xSemaphoreCreateBinary();
|
||||
MB_PORT_CHECK((xMasterSemaRxHandle != NULL), FALSE , "%s: RX semaphore create failure.", __func__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void vMBMasterPortRxSemaClose( void )
|
||||
{
|
||||
if (xMasterSemaRxHandle) {
|
||||
vSemaphoreDelete(xMasterSemaRxHandle);
|
||||
xMasterSemaRxHandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL xMBMasterPortRxSemaTake( LONG lTimeOut )
|
||||
{
|
||||
BaseType_t xStatus = pdTRUE;
|
||||
xStatus = xSemaphoreTake(xMasterSemaRxHandle, lTimeOut );
|
||||
MB_PORT_CHECK((xStatus == pdTRUE), FALSE , "%s: RX semaphore take failure.", __func__);
|
||||
ESP_LOGV(MB_PORT_TAG,"%s:Take RX semaphore (%" PRIu64 " ticks).", __func__, (uint64_t)lTimeOut);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void vMBMasterRxSemaRelease( void )
|
||||
{
|
||||
BaseType_t xStatus = pdFALSE;
|
||||
xStatus = xSemaphoreGive(xMasterSemaRxHandle);
|
||||
if (xStatus != pdTRUE) {
|
||||
ESP_LOGD(MB_PORT_TAG,"%s:RX semaphore is free.", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL vMBMasterRxSemaIsBusy( void )
|
||||
{
|
||||
BaseType_t xStatus = pdFALSE;
|
||||
xStatus = (uxSemaphoreGetCount(xMasterSemaRxHandle) == 0) ? TRUE : FALSE;
|
||||
return xStatus;
|
||||
}
|
||||
|
||||
void vMBMasterRxFlush( void )
|
||||
{
|
||||
size_t xSize = 1;
|
||||
esp_err_t xErr = ESP_OK;
|
||||
for (int xCount = 0; (xCount < MB_SERIAL_RX_FLUSH_RETRY) && xSize; xCount++) {
|
||||
xErr = uart_get_buffered_data_len(ucUartNumber, &xSize);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", (int)xErr);
|
||||
BaseType_t xStatus = xQueueReset(xMbUartQueue);
|
||||
if (xStatus) {
|
||||
xErr = uart_flush_input(ucUartNumber);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", (int)xErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
|
||||
{
|
||||
// This function can be called from xMBRTUTransmitFSM() of different task
|
||||
if (bTxEnable) {
|
||||
vMBMasterRxFlush();
|
||||
bTxStateEnabled = TRUE;
|
||||
} else {
|
||||
bTxStateEnabled = FALSE;
|
||||
}
|
||||
if (bRxEnable) {
|
||||
bRxStateEnabled = TRUE;
|
||||
vMBMasterRxSemaRelease();
|
||||
vTaskResume(xMbTaskHandle); // Resume receiver task
|
||||
} else {
|
||||
vTaskSuspend(xMbTaskHandle); // Block receiver task
|
||||
@ -85,24 +147,29 @@ void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
|
||||
|
||||
static USHORT usMBMasterPortSerialRxPoll(size_t xEventSize)
|
||||
{
|
||||
BOOL xReadStatus = TRUE;
|
||||
BOOL xStatus = TRUE;
|
||||
USHORT usCnt = 0;
|
||||
|
||||
if (bRxStateEnabled) {
|
||||
while(xReadStatus && (usCnt++ <= xEventSize)) {
|
||||
xStatus = xMBMasterPortRxSemaTake(MB_SERIAL_RX_SEMA_TOUT);
|
||||
if (xStatus) {
|
||||
while(xStatus && (usCnt++ <= xEventSize)) {
|
||||
// Call the Modbus stack callback function and let it fill the stack buffers.
|
||||
xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM
|
||||
xStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM
|
||||
}
|
||||
|
||||
// The buffer is transferred into Modbus stack and is not needed here any more
|
||||
uart_flush_input(ucUartNumber);
|
||||
ESP_LOGD(TAG, "Received data: %d(bytes in buffer)\n", (uint32_t)usCnt);
|
||||
ESP_LOGD(TAG, "Received data: %u(bytes in buffer)", (unsigned)usCnt);
|
||||
#if !CONFIG_FMB_TIMER_PORT_ENABLED
|
||||
vMBMasterSetCurTimerMode(MB_TMODE_T35);
|
||||
pxMBMasterPortCBTimerExpired();
|
||||
xStatus = pxMBMasterPortCBTimerExpired();
|
||||
if (!xStatus) {
|
||||
xMBMasterPortEventPost(EV_MASTER_FRAME_RECEIVED);
|
||||
ESP_LOGD(TAG, "Send additional RX ready event.");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: bRxState disabled but junk data (%d bytes) received. ", __func__, xEventSize);
|
||||
ESP_LOGE(TAG, "%s: bRxState disabled but junk data (%u bytes) received. ",
|
||||
__func__, (unsigned)xEventSize);
|
||||
}
|
||||
return usCnt;
|
||||
}
|
||||
@ -118,7 +185,7 @@ BOOL xMBMasterPortSerialTxPoll(void)
|
||||
// Calls the modbus stack callback function to let it fill the UART transmit buffer.
|
||||
bNeedPoll = pxMBMasterFrameCBTransmitterEmpty( ); // callback to transmit FSM
|
||||
}
|
||||
ESP_LOGD(TAG, "MB_TX_buffer sent: (%d) bytes.", (uint16_t)(usCount - 1));
|
||||
ESP_LOGD(TAG, "MB_TX_buffer sent: (%u) bytes.", (unsigned)(usCount - 1));
|
||||
// Waits while UART sending the packet
|
||||
esp_err_t xTxStatus = uart_wait_tx_done(ucUartNumber, MB_SERIAL_TX_TOUT_TICKS);
|
||||
vMBMasterPortSerialEnable(TRUE, FALSE);
|
||||
@ -135,21 +202,25 @@ static void vUartTask(void* pvParameters)
|
||||
USHORT usResult = 0;
|
||||
for(;;) {
|
||||
if (xMBPortSerialWaitEvent(xMbUartQueue, (void*)&xEvent, portMAX_DELAY)) {
|
||||
ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber);
|
||||
ESP_LOGD(TAG, "MB_uart[%u] event:", (unsigned)ucUartNumber);
|
||||
switch(xEvent.type) {
|
||||
//Event of UART receiving data
|
||||
case UART_DATA:
|
||||
ESP_LOGD(TAG,"Data event, len: %d.", xEvent.size);
|
||||
ESP_LOGD(TAG,"Data event, len: %u.", (unsigned)xEvent.size);
|
||||
// This flag set in the event means that no more
|
||||
// data received during configured timeout and UART TOUT feature is triggered
|
||||
if (xEvent.timeout_flag) {
|
||||
// Response is received but previous packet processing is pending
|
||||
// Do not wait completion of processing and just discard received data as incorrect
|
||||
if (vMBMasterRxSemaIsBusy()) {
|
||||
vMBMasterRxFlush();
|
||||
break;
|
||||
}
|
||||
// Get buffered data length
|
||||
ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size));
|
||||
// Read received data and send it to modbus stack
|
||||
usResult = usMBMasterPortSerialRxPoll(xEvent.size);
|
||||
ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult);
|
||||
// Block receiver task until data is not processed
|
||||
vTaskSuspend(NULL);
|
||||
ESP_LOGD(TAG,"Timeout occured, processed: %u bytes", (unsigned)usResult);
|
||||
}
|
||||
break;
|
||||
//Event of HW FIFO overflow detected
|
||||
@ -170,13 +241,17 @@ static void vUartTask(void* pvParameters)
|
||||
//Event of UART parity check error
|
||||
case UART_PARITY_ERR:
|
||||
ESP_LOGD(TAG, "uart parity error.");
|
||||
xQueueReset(xMbUartQueue);
|
||||
uart_flush_input(ucUartNumber);
|
||||
break;
|
||||
//Event of UART frame error
|
||||
case UART_FRAME_ERR:
|
||||
ESP_LOGD(TAG, "uart frame error.");
|
||||
xQueueReset(xMbUartQueue);
|
||||
uart_flush_input(ucUartNumber);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(TAG, "uart event type: %d.", xEvent.type);
|
||||
ESP_LOGD(TAG, "uart event type: %u.", (unsigned)xEvent.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -204,7 +279,7 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
ucParity = UART_PARITY_EVEN;
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Incorrect parity option: %d", eParity);
|
||||
ESP_LOGE(TAG, "Incorrect parity option: %u", (unsigned)eParity);
|
||||
return FALSE;
|
||||
}
|
||||
switch(ucDataBits){
|
||||
@ -231,25 +306,30 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 2,
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0))
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
#else
|
||||
.source_clk = UART_SCLK_APB,
|
||||
#endif
|
||||
};
|
||||
// Set UART config
|
||||
xErr = uart_param_config(ucUartNumber, &xUartConfig);
|
||||
MB_PORT_CHECK((xErr == ESP_OK),
|
||||
FALSE, "mb config failure, uart_param_config() returned (0x%x).", xErr);
|
||||
FALSE, "mb config failure, uart_param_config() returned (0x%x).", (int)xErr);
|
||||
// Install UART driver, and get the queue.
|
||||
xErr = uart_driver_install(ucUartNumber, MB_SERIAL_BUF_SIZE, MB_SERIAL_BUF_SIZE,
|
||||
MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
|
||||
"mb serial driver failure, uart_driver_install() returned (0x%x).", xErr);
|
||||
"mb serial driver failure, uart_driver_install() returned (0x%x).", (int)xErr);
|
||||
// Set timeout for TOUT interrupt (T3.5 modbus time)
|
||||
xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
|
||||
"mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr);
|
||||
"mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", (int)xErr);
|
||||
|
||||
// Set always timeout flag to trigger timeout interrupt even after rx fifo full
|
||||
uart_set_always_rx_timeout(ucUartNumber, true);
|
||||
|
||||
MB_PORT_CHECK((xMBMasterPortRxSemaInit()), FALSE,
|
||||
"mb serial RX semaphore create fail.");
|
||||
// Create a task to handle UART events
|
||||
BaseType_t xStatus = xTaskCreatePinnedToCore(vUartTask, "uart_queue_task",
|
||||
MB_SERIAL_TASK_STACK_SIZE,
|
||||
@ -259,8 +339,7 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
vTaskDelete(xMbTaskHandle);
|
||||
// Force exit from function with failure
|
||||
MB_PORT_CHECK(FALSE, FALSE,
|
||||
"mb stack serial task creation error. xTaskCreate() returned (0x%x).",
|
||||
xStatus);
|
||||
"mb stack serial task creation error. xTaskCreate() returned (0x%x).", (int)xStatus);
|
||||
} else {
|
||||
vTaskSuspend(xMbTaskHandle); // Suspend serial task while stack is not started
|
||||
}
|
||||
@ -268,26 +347,9 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function is called from ASCII/RTU module to get processed data buffer. Sets the
|
||||
* received buffer and its length using parameters.
|
||||
*/
|
||||
BOOL xMBMasterSerialPortGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function is called from ASCII/RTU module to set processed data buffer
|
||||
* to be sent in transmitter state machine.
|
||||
*/
|
||||
BOOL xMBMasterSerialPortSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBMasterPortSerialClose(void)
|
||||
{
|
||||
vMBMasterPortRxSemaClose();
|
||||
(void)vTaskDelete(xMbTaskHandle);
|
||||
ESP_ERROR_CHECK(uart_driver_delete(ucUartNumber));
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ static void IRAM_ATTR vTimerAlarmCBHandler(void *param)
|
||||
{
|
||||
pxMBMasterPortCBTimerExpired(); // Timer expired callback function
|
||||
pxTimerContext->xTimerState = TRUE;
|
||||
ESP_EARLY_LOGD(TAG, "Timer mode: (%d) triggered", xMBMasterGetCurTimerMode());
|
||||
ESP_EARLY_LOGD(TAG, "Timer mode: (%u) triggered", (unsigned)xMBMasterGetCurTimerMode());
|
||||
}
|
||||
|
||||
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
|
||||
@ -101,14 +101,12 @@ static BOOL xMBMasterPortTimersEnable(uint64_t xToutUs)
|
||||
|
||||
void vMBMasterPortTimersT35Enable(void)
|
||||
{
|
||||
#if CONFIG_FMB_TIMER_PORT_ENABLED
|
||||
uint64_t xToutUs = (pxTimerContext->usT35Ticks * MB_TIMER_TICK_TIME_US);
|
||||
|
||||
// Set current timer mode, don't change it.
|
||||
vMBMasterSetCurTimerMode(MB_TMODE_T35);
|
||||
// Set timer alarm
|
||||
(void)xMBMasterPortTimersEnable(xToutUs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vMBMasterPortTimersConvertDelayEnable(void)
|
||||
|
@ -27,8 +27,8 @@
|
||||
extern BOOL xMBMasterPortSerialTxPoll(void);
|
||||
|
||||
/*-----------------------Master mode use these variables----------------------*/
|
||||
#define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + 10)
|
||||
|
||||
// Actual wait time depends on the response timer
|
||||
#define MB_SERIAL_API_RESP_TICS (pdMS_TO_TICKS(MB_MAX_RESPONSE_TIME_MS))
|
||||
|
||||
static mb_master_interface_t* mbm_interface_ptr = NULL;
|
||||
static const char *TAG = "MB_CONTROLLER_MASTER";
|
||||
@ -71,12 +71,11 @@ static esp_err_t mbc_serial_master_setup(void* comm_info)
|
||||
const mb_master_comm_info_t* comm_info_ptr = (mb_master_comm_info_t*)comm_info;
|
||||
// Check communication options
|
||||
MB_MASTER_CHECK(((comm_info_ptr->mode == MB_MODE_RTU) || (comm_info_ptr->mode == MB_MODE_ASCII)),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (0x%x).",
|
||||
(uint32_t)comm_info_ptr->mode);
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (%u).", (unsigned)comm_info_ptr->mode);
|
||||
MB_MASTER_CHECK((comm_info_ptr->port <= UART_NUM_MAX), ESP_ERR_INVALID_ARG,
|
||||
"mb wrong port to set = (0x%x).", (uint32_t)comm_info_ptr->port);
|
||||
"mb wrong port to set = (%u).", (unsigned)comm_info_ptr->port);
|
||||
MB_MASTER_CHECK((comm_info_ptr->parity <= UART_PARITY_ODD), ESP_ERR_INVALID_ARG,
|
||||
"mb wrong parity option = (0x%x).", (uint32_t)comm_info_ptr->parity);
|
||||
"mb wrong parity option = (%u).", (unsigned)comm_info_ptr->parity);
|
||||
// Save the communication options
|
||||
mbm_opts->mbm_comm = *(mb_communication_info_t*)comm_info_ptr;
|
||||
return ESP_OK;
|
||||
@ -98,10 +97,10 @@ static esp_err_t mbc_serial_master_start(void)
|
||||
MB_PORT_PARITY_GET(comm_info->parity));
|
||||
|
||||
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack initialization failure, eMBInit() returns (0x%x).", status);
|
||||
"mb stack initialization failure, eMBInit() returns (0x%x).", (int)status);
|
||||
status = eMBMasterEnable();
|
||||
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);
|
||||
"mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (int)status);
|
||||
// Set the mbcontroller start flag
|
||||
EventBits_t flag = xEventGroupSetBits(mbm_opts->mbm_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
@ -122,7 +121,7 @@ static esp_err_t mbc_serial_master_destroy(void)
|
||||
EventBits_t flag = xEventGroupClearBits(mbm_opts->mbm_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
MB_MASTER_CHECK((flag & MB_EVENT_STACK_STARTED),
|
||||
ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
|
||||
ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
|
||||
// Desable and then destroy the Modbus stack
|
||||
mb_error = eMBMasterDisable();
|
||||
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
|
||||
@ -130,7 +129,7 @@ static esp_err_t mbc_serial_master_destroy(void)
|
||||
(void)vEventGroupDelete(mbm_opts->mbm_event_group);
|
||||
mb_error = eMBMasterClose();
|
||||
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack close failure returned (0x%x).", (uint32_t)mb_error);
|
||||
"mb stack close failure returned (0x%x).", (int)mb_error);
|
||||
free(mbm_interface_ptr); // free the memory allocated for options
|
||||
vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
|
||||
mbm_interface_ptr = NULL;
|
||||
@ -174,66 +173,70 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
|
||||
MB_MASTER_CHECK((data_ptr != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect data pointer.");
|
||||
|
||||
eMBMasterReqErrCode mb_error = MB_MRE_NO_REG;
|
||||
eMBMasterReqErrCode mb_error = MB_MRE_MASTER_BUSY;
|
||||
esp_err_t error = ESP_FAIL;
|
||||
|
||||
uint8_t mb_slave_addr = request->slave_addr;
|
||||
uint8_t mb_command = request->command;
|
||||
uint16_t mb_offset = request->reg_start;
|
||||
uint16_t mb_size = request->reg_size;
|
||||
if (xMBMasterRunResTake(MB_SERIAL_API_RESP_TICS)) {
|
||||
|
||||
uint8_t mb_slave_addr = request->slave_addr;
|
||||
uint8_t mb_command = request->command;
|
||||
uint16_t mb_offset = request->reg_start;
|
||||
uint16_t mb_size = request->reg_size;
|
||||
|
||||
// Set the buffer for callback function processing of received data
|
||||
mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
|
||||
mbm_opts->mbm_reg_buffer_size = mb_size;
|
||||
|
||||
// Set the buffer for callback function processing of received data
|
||||
mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
|
||||
mbm_opts->mbm_reg_buffer_size = mb_size;
|
||||
vMBMasterRunResRelease();
|
||||
|
||||
// Calls appropriate request function to send request and waits response
|
||||
switch(mb_command)
|
||||
{
|
||||
case MB_FUNC_READ_COILS:
|
||||
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size , (LONG)MB_RESPONSE_TICS );
|
||||
break;
|
||||
case MB_FUNC_WRITE_SINGLE_COIL:
|
||||
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
|
||||
break;
|
||||
case MB_FUNC_WRITE_MULTIPLE_COILS:
|
||||
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (UCHAR*)data_ptr, (LONG)MB_RESPONSE_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_DISCRETE_INPUTS:
|
||||
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
|
||||
break;
|
||||
case MB_FUNC_READ_HOLDING_REGISTER:
|
||||
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
|
||||
break;
|
||||
case MB_FUNC_WRITE_REGISTER:
|
||||
mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
|
||||
break;
|
||||
// Calls appropriate request function to send request and waits response
|
||||
switch(mb_command)
|
||||
{
|
||||
case MB_FUNC_READ_COILS:
|
||||
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size , (LONG)MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
case MB_FUNC_WRITE_SINGLE_COIL:
|
||||
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
case MB_FUNC_WRITE_MULTIPLE_COILS:
|
||||
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (UCHAR*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_DISCRETE_INPUTS:
|
||||
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
case MB_FUNC_READ_HOLDING_REGISTER:
|
||||
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
case MB_FUNC_WRITE_REGISTER:
|
||||
mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
|
||||
case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
|
||||
break;
|
||||
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (USHORT*)data_ptr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(LONG)MB_RESPONSE_TICS );
|
||||
break;
|
||||
case MB_FUNC_READ_INPUT_REGISTER:
|
||||
mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
|
||||
__FUNCTION__, mb_command);
|
||||
mb_error = MB_MRE_NO_REG;
|
||||
break;
|
||||
case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(USHORT*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (USHORT*)data_ptr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(LONG)MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
case MB_FUNC_READ_INPUT_REGISTER:
|
||||
mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG) MB_SERIAL_API_RESP_TICS );
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ", __FUNCTION__, (unsigned)mb_command);
|
||||
mb_error = MB_MRE_NO_REG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate the Modbus errors to higher level
|
||||
@ -261,8 +264,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ",
|
||||
__FUNCTION__, mb_error);
|
||||
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, (int)mb_error);
|
||||
error = ESP_FAIL;
|
||||
break;
|
||||
}
|
||||
@ -316,13 +318,11 @@ static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_para
|
||||
if (mode != MB_PARAM_WRITE) {
|
||||
command = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: Incorrect mode (%u)",
|
||||
__FUNCTION__, (uint8_t)mode);
|
||||
ESP_LOGE(TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (unsigned)mode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u)",
|
||||
__FUNCTION__, param_type);
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, (unsigned)param_type);
|
||||
break;
|
||||
}
|
||||
return command;
|
||||
@ -363,8 +363,7 @@ static esp_err_t mbc_serial_master_set_request(char* name, mb_param_mode_t mode,
|
||||
request->reg_start = reg_ptr->mb_reg_start;
|
||||
request->reg_size = reg_ptr->mb_size;
|
||||
request->command = mbc_serial_master_get_command(reg_ptr->mb_param_type, mode);
|
||||
MB_MASTER_CHECK((request->command > 0),
|
||||
ESP_ERR_INVALID_ARG,
|
||||
MB_MASTER_CHECK((request->command > 0), ESP_ERR_INVALID_ARG,
|
||||
"mb incorrect command or parameter type.");
|
||||
if (reg_data != NULL) {
|
||||
*reg_data = *reg_ptr; // Set the cid registered parameter data
|
||||
@ -394,16 +393,16 @@ static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
|
||||
error = mbc_serial_master_send_request(&request, value_ptr);
|
||||
if (error == ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
|
||||
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
|
||||
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
}
|
||||
// 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__, reg_info.cid);
|
||||
__FUNCTION__, (unsigned)reg_info.cid);
|
||||
error = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return error;
|
||||
@ -429,16 +428,16 @@ static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
|
||||
error = mbc_serial_master_send_request(&request, value_ptr);
|
||||
if (error == ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
|
||||
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
|
||||
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
}
|
||||
// Set the type of parameter found in the table
|
||||
*type = reg_info.param_type;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
|
||||
__FUNCTION__, reg_info.cid);
|
||||
__FUNCTION__, (unsigned)reg_info.cid);
|
||||
error = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return error;
|
||||
@ -550,9 +549,9 @@ eMBErrorCode eMBRegCoilsCBSerialMaster(UCHAR* pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNCoils, eMBRegisterMode eMode)
|
||||
{
|
||||
MB_MASTER_CHECK((mbm_interface_ptr != NULL),
|
||||
MB_EILLSTATE, "Master interface uninitialized.");
|
||||
MB_EILLSTATE, "Master interface uninitialized.");
|
||||
MB_MASTER_CHECK((pucRegBuffer != NULL),
|
||||
MB_EINVAL, "Master stack processing error.");
|
||||
MB_EINVAL, "Master stack processing error.");
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
USHORT usRegCoilNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
|
||||
UCHAR* pucRegCoilsBuf = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
|
||||
@ -675,8 +674,7 @@ esp_err_t mbc_serial_master_create(void** handler)
|
||||
if (status != pdPASS) {
|
||||
vTaskDelete(mbm_opts->mbm_task_handle);
|
||||
MB_MASTER_CHECK((status == pdPASS), ESP_ERR_NO_MEM,
|
||||
"mb controller task creation error, xTaskCreate() returns (0x%x).",
|
||||
(uint32_t)status);
|
||||
"mb controller task creation error, xTaskCreate() returns (0x%x).", (int)status);
|
||||
}
|
||||
MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
|
||||
|
||||
|
@ -59,15 +59,14 @@ static esp_err_t mbc_serial_slave_setup(void* comm_info)
|
||||
mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts;
|
||||
mb_slave_comm_info_t* comm_settings = (mb_slave_comm_info_t*)comm_info;
|
||||
MB_SLAVE_CHECK(((comm_settings->mode == MB_MODE_RTU) || (comm_settings->mode == MB_MODE_ASCII)),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (0x%x).",
|
||||
(uint32_t)comm_settings->mode);
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (%u).",
|
||||
(unsigned)comm_settings->mode);
|
||||
MB_SLAVE_CHECK((comm_settings->slave_addr <= MB_ADDRESS_MAX),
|
||||
ESP_ERR_INVALID_ARG, "mb wrong slave address = (0x%x).",
|
||||
(uint32_t)comm_settings->slave_addr);
|
||||
ESP_ERR_INVALID_ARG, "mb wrong slave address = (%u).", (unsigned)comm_settings->slave_addr);
|
||||
MB_SLAVE_CHECK((comm_settings->port < UART_NUM_MAX), ESP_ERR_INVALID_ARG,
|
||||
"mb wrong port to set = (0x%x).", (uint32_t)comm_settings->port);
|
||||
"mb wrong port to set = (%u).", (unsigned)comm_settings->port);
|
||||
MB_SLAVE_CHECK((comm_settings->parity <= UART_PARITY_ODD), ESP_ERR_INVALID_ARG,
|
||||
"mb wrong parity option = (0x%x).", (uint32_t)comm_settings->parity);
|
||||
"mb wrong parity option = (%u).", (unsigned)comm_settings->parity);
|
||||
|
||||
// Set communication options of the controller
|
||||
mbs_opts->mbs_comm = *(mb_communication_info_t*)comm_settings;
|
||||
@ -92,10 +91,10 @@ static esp_err_t mbc_serial_slave_start(void)
|
||||
MB_PORT_PARITY_GET(comm_info->parity));
|
||||
|
||||
MB_SLAVE_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack initialization failure, eMBInit() returns (0x%x).", status);
|
||||
"mb stack initialization failure, eMBInit() returns (0x%x).", (int)status);
|
||||
status = eMBEnable();
|
||||
MB_SLAVE_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack set slave ID failure, eMBEnable() returned (0x%x).", (uint32_t)status);
|
||||
"mb stack set slave ID failure, eMBEnable() returned (0x%x).", (int)status);
|
||||
// Set the mbcontroller start flag
|
||||
EventBits_t flag = xEventGroupSetBits(mbs_opts->mbs_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
@ -154,7 +153,7 @@ static esp_err_t mbc_serial_slave_destroy(void)
|
||||
EventBits_t flag = xEventGroupClearBits(mbs_opts->mbs_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
MB_SLAVE_CHECK((flag & MB_EVENT_STACK_STARTED),
|
||||
ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
|
||||
ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
|
||||
// Disable and then destroy the Modbus stack
|
||||
mb_error = eMBDisable();
|
||||
MB_SLAVE_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
|
||||
@ -163,7 +162,7 @@ static esp_err_t mbc_serial_slave_destroy(void)
|
||||
(void)vEventGroupDelete(mbs_opts->mbs_event_group);
|
||||
mb_error = eMBClose();
|
||||
MB_SLAVE_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack close failure returned (0x%x).", (uint32_t)mb_error);
|
||||
"mb stack close failure returned (0x%x).", (int)mb_error);
|
||||
mbs_interface_ptr = NULL;
|
||||
vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
|
||||
return ESP_OK;
|
||||
@ -201,7 +200,7 @@ esp_err_t mbc_serial_slave_create(void** handler)
|
||||
MB_CONTROLLER_NOTIFY_QUEUE_SIZE,
|
||||
sizeof(mb_param_info_t));
|
||||
MB_SLAVE_CHECK((mbs_opts->mbs_notification_queue_handle != NULL),
|
||||
ESP_ERR_NO_MEM, "mb notify queue creation error.");
|
||||
ESP_ERR_NO_MEM, "mb notify queue creation error.");
|
||||
// Create Modbus controller task
|
||||
status = xTaskCreatePinnedToCore((void*)&modbus_slave_task,
|
||||
"modbus_slave_task",
|
||||
@ -213,8 +212,7 @@ esp_err_t mbc_serial_slave_create(void** handler)
|
||||
if (status != pdPASS) {
|
||||
vTaskDelete(mbs_opts->mbs_task_handle);
|
||||
MB_SLAVE_CHECK((status == pdPASS), ESP_ERR_NO_MEM,
|
||||
"mb controller task creation error, xTaskCreate() returns (0x%x).",
|
||||
(uint32_t)status);
|
||||
"mb controller task creation error, xTaskCreate() returns (0x%x).", (int)status);
|
||||
}
|
||||
MB_SLAVE_ASSERT(mbs_opts->mbs_task_handle != NULL); // The task is created but handle is incorrect
|
||||
|
||||
|
@ -29,9 +29,10 @@
|
||||
|
||||
/*-----------------------Master mode use these variables----------------------*/
|
||||
|
||||
// The response time is average processing time + data transmission
|
||||
#define MB_RESPONSE_TIMEOUT pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
|
||||
#define MB_TCP_CONNECTION_TOUT pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000)
|
||||
#define MB_TCP_CONNECTION_TOUT (pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000))
|
||||
|
||||
// Actual wait time depends on the response timer
|
||||
#define MB_TCP_API_RESP_TICS (pdMS_TO_TICKS(MB_MAX_RESPONSE_TIME_MS))
|
||||
|
||||
static mb_master_interface_t* mbm_interface_ptr = NULL;
|
||||
static const char *TAG = "MB_CONTROLLER_MASTER";
|
||||
@ -81,7 +82,7 @@ static void mbc_tcp_master_free_slave_list(void)
|
||||
// Initialize interface properties
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
|
||||
LIST_FOREACH(it, &mbm_opts->mbm_slave_list, entries) {
|
||||
while ((it = LIST_FIRST(&mbm_opts->mbm_slave_list))) {
|
||||
LIST_REMOVE(it, entries);
|
||||
mbm_opts->mbm_slave_list_count--;
|
||||
free(it);
|
||||
@ -120,12 +121,11 @@ static esp_err_t mbc_tcp_master_setup(void* comm_info)
|
||||
const mb_communication_info_t* comm_info_ptr = (mb_communication_info_t*)comm_info;
|
||||
// Check communication options
|
||||
MB_MASTER_CHECK((comm_info_ptr->ip_mode == MB_MODE_TCP),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (0x%x).",
|
||||
(uint32_t)comm_info_ptr->ip_mode);
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (%u).", (unsigned)comm_info_ptr->ip_mode);
|
||||
MB_MASTER_CHECK((comm_info_ptr->ip_addr != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb wrong slave ip address table.");
|
||||
MB_MASTER_CHECK(((comm_info_ptr->ip_addr_type == MB_IPV4) || (comm_info_ptr->ip_addr_type == MB_IPV6)),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect addr type = (0x%x).", (uint8_t)comm_info_ptr->ip_addr_type);
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect addr type = (%u).", (unsigned)comm_info_ptr->ip_addr_type);
|
||||
MB_MASTER_CHECK((comm_info_ptr->ip_netif_ptr != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect iface address.");
|
||||
// Save the communication options
|
||||
@ -159,7 +159,7 @@ static esp_err_t mbc_tcp_master_start(void)
|
||||
|
||||
status = eMBMasterEnable();
|
||||
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack enable failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);
|
||||
"mb stack enable failure, eMBMasterEnable() returned (0x%x).", (int)status);
|
||||
|
||||
// Add slave IP address for each slave to initialize connection
|
||||
mb_slave_addr_entry_t *p_slave_info;
|
||||
@ -194,7 +194,7 @@ static esp_err_t mbc_tcp_master_destroy(void)
|
||||
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
|
||||
mb_error = eMBMasterClose();
|
||||
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack close failure returned (0x%x).", (uint32_t)mb_error);
|
||||
"mb stack close failure returned (0x%x).", (int)mb_error);
|
||||
// Stop polling by clearing correspondent bit in the event group
|
||||
xEventGroupClearBits(mbm_opts->mbm_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
@ -237,7 +237,7 @@ static esp_err_t mbc_tcp_master_set_descriptor(const mb_parameter_descriptor_t*
|
||||
// Add it to slave list if not there.
|
||||
if (!p_slave) {
|
||||
// Is the IP address correctly defined for the slave?
|
||||
MB_MASTER_CHECK((comm_ip_table[slave_cnt]), ESP_ERR_INVALID_STATE, "mb missing IP address for cid #%d.", reg_ptr->cid);
|
||||
MB_MASTER_CHECK((comm_ip_table[slave_cnt]), ESP_ERR_INVALID_STATE, "mb missing IP address for cid #%u.", (unsigned)reg_ptr->cid);
|
||||
// Add slave to the list
|
||||
MB_MASTER_ASSERT(mbc_tcp_master_add_slave(idx, reg_ptr->mb_slave_addr, comm_ip_table[slave_cnt++]) == ESP_OK);
|
||||
}
|
||||
@ -255,68 +255,72 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
|
||||
MB_MASTER_CHECK((request != NULL), ESP_ERR_INVALID_ARG, "mb request structure.");
|
||||
MB_MASTER_CHECK((data_ptr != NULL), ESP_ERR_INVALID_ARG, "mb incorrect data pointer.");
|
||||
|
||||
eMBMasterReqErrCode mb_error = MB_MRE_NO_REG;
|
||||
eMBMasterReqErrCode mb_error = MB_MRE_MASTER_BUSY;
|
||||
esp_err_t error = ESP_FAIL;
|
||||
|
||||
uint8_t mb_slave_addr = request->slave_addr;
|
||||
uint8_t mb_command = request->command;
|
||||
uint16_t mb_offset = request->reg_start;
|
||||
uint16_t mb_size = request->reg_size;
|
||||
if (xMBMasterRunResTake(MB_TCP_API_RESP_TICS)) {
|
||||
|
||||
uint8_t mb_slave_addr = request->slave_addr;
|
||||
uint8_t mb_command = request->command;
|
||||
uint16_t mb_offset = request->reg_start;
|
||||
uint16_t mb_size = request->reg_size;
|
||||
|
||||
// Set the buffer for callback function processing of received data
|
||||
mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
|
||||
mbm_opts->mbm_reg_buffer_size = mb_size;
|
||||
|
||||
// Set the buffer for callback function processing of received data
|
||||
mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
|
||||
mbm_opts->mbm_reg_buffer_size = mb_size;
|
||||
vMBMasterRunResRelease();
|
||||
|
||||
// Calls appropriate request function to send request and waits response
|
||||
switch(mb_command)
|
||||
{
|
||||
case MB_FUNC_READ_COILS:
|
||||
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
case MB_FUNC_WRITE_SINGLE_COIL:
|
||||
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT *)data_ptr, (LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
case MB_FUNC_WRITE_MULTIPLE_COILS:
|
||||
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (UCHAR *)data_ptr,
|
||||
(LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
case MB_FUNC_READ_DISCRETE_INPUTS:
|
||||
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
case MB_FUNC_READ_HOLDING_REGISTER:
|
||||
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
case MB_FUNC_WRITE_REGISTER:
|
||||
mb_error = eMBMasterReqWriteHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT *)data_ptr, (LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
// Calls appropriate request function to send request and waits response
|
||||
switch(mb_command)
|
||||
{
|
||||
case MB_FUNC_READ_COILS:
|
||||
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_WRITE_SINGLE_COIL:
|
||||
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_WRITE_MULTIPLE_COILS:
|
||||
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (UCHAR *)data_ptr,
|
||||
(LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_DISCRETE_INPUTS:
|
||||
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_HOLDING_REGISTER:
|
||||
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_WRITE_REGISTER:
|
||||
mb_error = eMBMasterReqWriteHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
|
||||
case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqWriteMultipleHoldingRegister((UCHAR)mb_slave_addr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(USHORT *)data_ptr, (LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (USHORT *)data_ptr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
case MB_FUNC_READ_INPUT_REGISTER:
|
||||
mb_error = eMBMasterReqReadInputRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
|
||||
__FUNCTION__, mb_command);
|
||||
mb_error = MB_MRE_NO_REG;
|
||||
break;
|
||||
}
|
||||
case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqWriteMultipleHoldingRegister((UCHAR)mb_slave_addr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
|
||||
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (USHORT *)data_ptr,
|
||||
(USHORT)mb_offset, (USHORT)mb_size,
|
||||
(LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_INPUT_REGISTER:
|
||||
mb_error = eMBMasterReqReadInputRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ", __FUNCTION__, (unsigned)mb_command);
|
||||
mb_error = MB_MRE_NO_REG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate the Modbus errors to higher level
|
||||
switch(mb_error)
|
||||
@ -343,7 +347,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, mb_error);
|
||||
ESP_LOGE(TAG, "%s: Incorrect return code (0x%x) ", __FUNCTION__, (unsigned)mb_error);
|
||||
error = ESP_FAIL;
|
||||
break;
|
||||
}
|
||||
@ -387,11 +391,11 @@ static uint8_t mbc_tcp_master_get_command(mb_param_type_t param_type, mb_param_m
|
||||
if (mode != MB_PARAM_WRITE) {
|
||||
command = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (uint8_t)mode);
|
||||
ESP_LOGE(TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (unsigned)mode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, param_type);
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, (unsigned)param_type);
|
||||
break;
|
||||
}
|
||||
return command;
|
||||
@ -423,7 +427,7 @@ static esp_err_t mbc_tcp_master_set_param_data(void* dest, void* src, mb_descr_t
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u).",
|
||||
__FUNCTION__, (uint16_t)param_type);
|
||||
__FUNCTION__, (unsigned)param_type);
|
||||
err = ESP_ERR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
@ -503,15 +507,13 @@ static esp_err_t mbc_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t*
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
|
||||
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
||||
error = ESP_ERR_INVALID_RESPONSE;
|
||||
__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__, 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;
|
||||
@ -550,14 +552,14 @@ static esp_err_t mbc_tcp_master_set_parameter(uint16_t cid, char* name, uint8_t*
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
|
||||
__FUNCTION__, 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 requested cid(%u) not found in the data dictionary.",
|
||||
__FUNCTION__, reg_info.cid);
|
||||
__FUNCTION__, (unsigned)reg_info.cid);
|
||||
error = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return error;
|
||||
@ -782,8 +784,7 @@ esp_err_t mbc_tcp_master_create(void** handler)
|
||||
if (status != pdPASS) {
|
||||
vTaskDelete(mbm_opts->mbm_task_handle);
|
||||
MB_MASTER_CHECK((status == pdPASS), ESP_ERR_NO_MEM,
|
||||
"mb controller task creation error, xTaskCreate() returns (0x%x).",
|
||||
(uint32_t)status);
|
||||
"mb controller task creation error, xTaskCreate() returns (%u).", (unsigned)status);
|
||||
}
|
||||
MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
|
||||
|
||||
|
@ -74,7 +74,7 @@
|
||||
#define MB_SLAVE_FMT(fmt) "Slave #%d, Socket(#%d)(%s)"fmt
|
||||
|
||||
/* ----------------------- Types & Prototypes --------------------------------*/
|
||||
void vMBPortEventClose( void );
|
||||
void vMBPortEventClose(void);
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static const char *TAG = "MB_TCP_MASTER_PORT";
|
||||
@ -94,10 +94,10 @@ BOOL xMBTCPPortMasterWaitEvent(EventGroupHandle_t xEventHandle, EventBits_t xEve
|
||||
xMasterEventHandle = xEventHandle;
|
||||
xMasterEvent = xEvent;
|
||||
BaseType_t status = xEventGroupWaitBits(xMasterEventHandle,
|
||||
(BaseType_t)(xEvent),
|
||||
pdFALSE, // do not clear start bit
|
||||
pdFALSE,
|
||||
usTimeout);
|
||||
(BaseType_t)(xEvent),
|
||||
pdFALSE, // do not clear start bit
|
||||
pdFALSE,
|
||||
usTimeout);
|
||||
return (BOOL)(status & xEvent);
|
||||
}
|
||||
|
||||
@ -129,12 +129,12 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
|
||||
|
||||
// Create task for packet processing
|
||||
BaseType_t xErr = xTaskCreatePinnedToCore(vMBTCPPortMasterTask,
|
||||
"tcp_master_task",
|
||||
MB_TCP_STACK_SIZE,
|
||||
NULL,
|
||||
MB_TCP_TASK_PRIO,
|
||||
&xMbPortConfig.xMbTcpTaskHandle,
|
||||
MB_PORT_TASK_AFFINITY);
|
||||
"tcp_master_task",
|
||||
MB_TCP_STACK_SIZE,
|
||||
NULL,
|
||||
MB_TCP_TASK_PRIO,
|
||||
&xMbPortConfig.xMbTcpTaskHandle,
|
||||
MB_PORT_TASK_AFFINITY);
|
||||
if (xErr != pdTRUE)
|
||||
{
|
||||
ESP_LOGE(TAG, "TCP master task creation failure.");
|
||||
@ -148,7 +148,7 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
|
||||
return bOkay;
|
||||
}
|
||||
|
||||
static MbSlaveInfo_t* vMBTCPPortMasterFindSlaveInfo(UCHAR ucSlaveAddr)
|
||||
static MbSlaveInfo_t *vMBTCPPortMasterFindSlaveInfo(UCHAR ucSlaveAddr)
|
||||
{
|
||||
int xIndex;
|
||||
BOOL xFound = false;
|
||||
@ -161,12 +161,12 @@ static MbSlaveInfo_t* vMBTCPPortMasterFindSlaveInfo(UCHAR ucSlaveAddr)
|
||||
}
|
||||
if (!xFound) {
|
||||
xMbPortConfig.pxMbSlaveCurrInfo = NULL;
|
||||
ESP_LOGE(TAG, "Slave info for short address %d not found.", ucSlaveAddr);
|
||||
ESP_LOGE(TAG, "Slave info for short address %u not found.", ucSlaveAddr);
|
||||
}
|
||||
return xMbPortConfig.pxMbSlaveCurrInfo;
|
||||
}
|
||||
|
||||
static MbSlaveInfo_t* vMBTCPPortMasterGetCurrInfo(void)
|
||||
static MbSlaveInfo_t *vMBTCPPortMasterGetCurrInfo(void)
|
||||
{
|
||||
if (!xMbPortConfig.pxMbSlaveCurrInfo) {
|
||||
ESP_LOGE(TAG, "Incorrect current slave info.");
|
||||
@ -217,7 +217,8 @@ static void vMBTCPPortMasterMStoTimeVal(USHORT usTimeoutMs, struct timeval *tv)
|
||||
tv->tv_usec = (usTimeoutMs - (tv->tv_sec * 1000)) * 1000;
|
||||
}
|
||||
|
||||
static void xMBTCPPortMasterCheckShutdown(void) {
|
||||
static void xMBTCPPortMasterCheckShutdown(void)
|
||||
{
|
||||
// First check if the task is not flagged for shutdown
|
||||
if (xShutdownSemaphore) {
|
||||
xSemaphoreGive(xShutdownSemaphore);
|
||||
@ -225,24 +226,24 @@ static void xMBTCPPortMasterCheckShutdown(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t* pxInfo)
|
||||
static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t *pxInfo)
|
||||
{
|
||||
if (!pxInfo) {
|
||||
return FALSE;
|
||||
}
|
||||
if (pxInfo->xSockId == -1) {
|
||||
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d, skip.", pxInfo->xSockId);
|
||||
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d, skip.", (int)pxInfo->xSockId);
|
||||
return FALSE;
|
||||
}
|
||||
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
|
||||
ESP_LOGV(TAG, "Shutdown failed sock %d, errno=%d", pxInfo->xSockId, errno);
|
||||
ESP_LOGV(TAG, "Shutdown failed sock %d, errno=%u", (int)pxInfo->xSockId, (unsigned)errno);
|
||||
}
|
||||
close(pxInfo->xSockId);
|
||||
pxInfo->xSockId = -1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBTCPPortMasterSetNetOpt(void* pvNetIf, eMBPortIpVer xIpVersion, eMBPortProto xProto)
|
||||
void vMBTCPPortMasterSetNetOpt(void *pvNetIf, eMBPortIpVer xIpVersion, eMBPortProto xProto)
|
||||
{
|
||||
xMbPortConfig.pvNetIface = pvNetIf;
|
||||
xMbPortConfig.eMbProto = xProto;
|
||||
@ -250,7 +251,7 @@ void vMBTCPPortMasterSetNetOpt(void* pvNetIf, eMBPortIpVer xIpVersion, eMBPortPr
|
||||
}
|
||||
|
||||
// Function returns time left for response processing according to response timeout
|
||||
static int64_t xMBTCPPortMasterGetRespTimeLeft(MbSlaveInfo_t* pxInfo)
|
||||
static int64_t xMBTCPPortMasterGetRespTimeLeft(MbSlaveInfo_t *pxInfo)
|
||||
{
|
||||
if (!pxInfo) {
|
||||
return 0;
|
||||
@ -261,7 +262,7 @@ static int64_t xMBTCPPortMasterGetRespTimeLeft(MbSlaveInfo_t* pxInfo)
|
||||
}
|
||||
|
||||
// Wait socket ready to read state
|
||||
static int vMBTCPPortMasterRxCheck(int xSd, fd_set* pxFdSet, int xTimeMs)
|
||||
static int vMBTCPPortMasterRxCheck(int xSd, fd_set *pxFdSet, int xTimeMs)
|
||||
{
|
||||
fd_set xReadSet = *pxFdSet;
|
||||
fd_set xErrorSet = *pxFdSet;
|
||||
@ -281,32 +282,36 @@ static int vMBTCPPortMasterRxCheck(int xSd, fd_set* pxFdSet, int xTimeMs)
|
||||
return xRes;
|
||||
}
|
||||
|
||||
static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t* pxInfo, UCHAR* pucDstBuf, USHORT usLength)
|
||||
static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t *pxInfo, UCHAR *pucDstBuf, USHORT usLength, uint16_t xTimeMs)
|
||||
{
|
||||
int xLength = 0;
|
||||
UCHAR* pucBuf = pucDstBuf;
|
||||
UCHAR *pucBuf = pucDstBuf;
|
||||
USHORT usBytesLeft = usLength;
|
||||
struct timeval xTime;
|
||||
|
||||
MB_PORT_CHECK((pxInfo && pxInfo->xSockId > -1), -1, "Try to read incorrect socket = #%d.", pxInfo->xSockId);
|
||||
MB_PORT_CHECK((pxInfo && pxInfo->xSockId > -1), -1, "Try to read incorrect socket = #%d.", (int)pxInfo->xSockId);
|
||||
|
||||
// Set receive timeout for socket <= slave respond time
|
||||
xTime.tv_sec = xTimeMs / 1000;
|
||||
xTime.tv_usec = (xTimeMs % 1000) * 1000;
|
||||
setsockopt(pxInfo->xSockId, SOL_SOCKET, SO_RCVTIMEO, &xTime, sizeof(xTime));
|
||||
|
||||
// Receive data from connected client
|
||||
while (usBytesLeft > 0) {
|
||||
xMBTCPPortMasterCheckShutdown();
|
||||
// none blocking read from socket with timeout
|
||||
xLength = recv(pxInfo->xSockId, pucBuf, usBytesLeft, MSG_DONTWAIT);
|
||||
xLength = recv(pxInfo->xSockId, pucBuf, usBytesLeft, 0);
|
||||
if (xLength < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
// Read timeout occurred, continue reading
|
||||
continue;
|
||||
// Read timeout occurred, check the timeout and return
|
||||
} else if (errno == ENOTCONN) {
|
||||
// Socket connection closed
|
||||
ESP_LOGE(TAG, "Socket(#%d)(%s) connection closed.",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr);
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr);
|
||||
return ERR_CONN;
|
||||
} else {
|
||||
// Other error occurred during receiving
|
||||
ESP_LOGE(TAG, "Socket(#%d)(%s) receive error, length=%d, errno=%d",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, xLength, errno);
|
||||
ESP_LOGE(TAG, "Socket(#%d)(%s) receive error, length=%u, errno=%u",
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (unsigned)xLength, (unsigned)errno);
|
||||
return -1;
|
||||
}
|
||||
} else if (xLength) {
|
||||
@ -316,12 +321,11 @@ static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t* pxInfo, UCHAR* pucDstBuf, USHOR
|
||||
if (xMBTCPPortMasterGetRespTimeLeft(pxInfo) == 0) {
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
vTaskDelay(1);
|
||||
}
|
||||
return usLength;
|
||||
}
|
||||
|
||||
static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
|
||||
static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t *pxInfo)
|
||||
{
|
||||
int xLength = 0;
|
||||
int xRet = 0;
|
||||
@ -331,28 +335,30 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
|
||||
if (pxInfo) {
|
||||
MB_PORT_CHECK((pxInfo->xSockId > 0), -1, "Try to read incorrect socket = #%d.", pxInfo->xSockId);
|
||||
// Read packet header
|
||||
xRet = xMBTCPPortMasterGetBuf(pxInfo, &pxInfo->pucRcvBuf[0], MB_TCP_UID);
|
||||
xRet = xMBTCPPortMasterGetBuf(pxInfo, &pxInfo->pucRcvBuf[0],
|
||||
MB_TCP_UID, xMBTCPPortMasterGetRespTimeLeft(pxInfo));
|
||||
if (xRet < 0) {
|
||||
pxInfo->xRcvErr = xRet;
|
||||
return xRet;
|
||||
} else if (xRet != MB_TCP_UID) {
|
||||
ESP_LOGD(TAG, "Socket (#%d)(%s), Fail to read modbus header. ret=%d",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, xRet);
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)xRet);
|
||||
pxInfo->xRcvErr = ERR_VAL;
|
||||
return ERR_VAL;
|
||||
}
|
||||
// If we have received the MBAP header we can analyze it and calculate
|
||||
// the number of bytes left to complete the current request.
|
||||
xLength = (int)MB_TCP_GET_FIELD(pxInfo->pucRcvBuf, MB_TCP_LEN);
|
||||
xRet = xMBTCPPortMasterGetBuf(pxInfo, &pxInfo->pucRcvBuf[MB_TCP_UID], xLength);
|
||||
xRet = xMBTCPPortMasterGetBuf(pxInfo, &pxInfo->pucRcvBuf[MB_TCP_UID],
|
||||
xLength, xMBTCPPortMasterGetRespTimeLeft(pxInfo));
|
||||
if (xRet < 0) {
|
||||
pxInfo->xRcvErr = xRet;
|
||||
return xRet;
|
||||
} else if (xRet != xLength) {
|
||||
// Received incorrect or fragmented packet.
|
||||
ESP_LOGD(TAG, "Socket(#%d)(%s) incorrect packet, length=%d, TID=0x%02x, errno=%d(%s)",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
|
||||
usTidRcv, errno, strerror(errno));
|
||||
ESP_LOGD(TAG, "Socket(#%d)(%s) incorrect packet, length=%u, TID=0x%02x, errno=%u(%s)",
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)pxInfo->usRcvPos,
|
||||
(int)usTidRcv, (unsigned)errno, strerror(errno));
|
||||
pxInfo->xRcvErr = ERR_VAL;
|
||||
return ERR_VAL;
|
||||
}
|
||||
@ -361,21 +367,21 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
|
||||
// Check transaction identifier field in the incoming packet.
|
||||
if ((pxInfo->usTidCnt - 1) != usTidRcv) {
|
||||
ESP_LOGD(TAG, "Socket (#%d)(%s), incorrect TID(0x%02x)!=(0x%02x) received, discard data.",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, usTidRcv, (pxInfo->usTidCnt - 1));
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)usTidRcv, (int)(pxInfo->usTidCnt - 1));
|
||||
pxInfo->xRcvErr = ERR_BUF;
|
||||
return ERR_BUF;
|
||||
}
|
||||
pxInfo->usRcvPos += xRet + MB_TCP_UID;
|
||||
ESP_LOGD(TAG, "Socket(#%d)(%s) get data, length=%d, TID=0x%02x, errno=%d(%s)",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
|
||||
usTidRcv, errno, strerror(errno));
|
||||
ESP_LOGD(TAG, "Socket(#%d)(%s) get data, length=%u, TID=0x%02x, errno=%u(%s)",
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (unsigned)pxInfo->usRcvPos,
|
||||
(unsigned)usTidRcv, (unsigned)errno, strerror(errno));
|
||||
pxInfo->xRcvErr = ERR_OK;
|
||||
return pxInfo->usRcvPos;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
|
||||
static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t *pxInfo)
|
||||
{
|
||||
if (!pxInfo) {
|
||||
return ERR_CONN;
|
||||
@ -383,21 +389,21 @@ static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
|
||||
// Set non blocking attribute for socket
|
||||
ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
|
||||
if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
|
||||
ESP_LOGE(TAG, "Socket(#%d)(%s), fcntl() call error=%d",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, errno);
|
||||
ESP_LOGE(TAG, "Socket(#%d)(%s), fcntl() call error=%u",
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (unsigned)errno);
|
||||
return ERR_WOULDBLOCK;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void vMBTCPPortSetKeepAlive(MbSlaveInfo_t* pxInfo)
|
||||
static void vMBTCPPortSetKeepAlive(MbSlaveInfo_t *pxInfo)
|
||||
{
|
||||
int optval = 1;
|
||||
setsockopt(pxInfo->xSockId, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
||||
}
|
||||
|
||||
// Check connection for timeout helper
|
||||
static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
|
||||
static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t *pxInfo, ULONG xTimeoutMs)
|
||||
{
|
||||
fd_set xWriteSet;
|
||||
fd_set xErrorSet;
|
||||
@ -416,13 +422,13 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
|
||||
if (errno == EINPROGRESS) {
|
||||
xErr = ERR_INPROGRESS;
|
||||
} else {
|
||||
ESP_LOGV(TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
|
||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
|
||||
ESP_LOGV(TAG, MB_SLAVE_FMT(" connection, select write err(errno) = 0x%x(%u)."),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)xErr, (unsigned)errno);
|
||||
xErr = ERR_CONN;
|
||||
}
|
||||
} else if (xErr == 0) {
|
||||
ESP_LOGV(TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
|
||||
ESP_LOGV(TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = 0x%x(%u).",
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)xErr, (unsigned)errno);
|
||||
return ERR_INPROGRESS;
|
||||
} else {
|
||||
int xOptErr = 0;
|
||||
@ -430,12 +436,12 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
|
||||
// Check socket error
|
||||
xErr = getsockopt(pxInfo->xSockId, SOL_SOCKET, SO_ERROR, (void*)&xOptErr, (socklen_t*)&ulOptLen);
|
||||
if (xOptErr != 0) {
|
||||
ESP_LOGD(TAG, "Socket(#%d)(%s), sock error occurred (%d).",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr, xOptErr);
|
||||
ESP_LOGD(TAG, "Socket(#%d)(%s), sock error occurred (%u).",
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr, (unsigned)xOptErr);
|
||||
return ERR_CONN;
|
||||
}
|
||||
ESP_LOGV(TAG, "Socket(#%d)(%s), is alive.",
|
||||
pxInfo->xSockId, pxInfo->pcIpAddr);
|
||||
(int)pxInfo->xSockId, pxInfo->pcIpAddr);
|
||||
return ERR_OK;
|
||||
}
|
||||
} else {
|
||||
@ -445,14 +451,14 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
|
||||
}
|
||||
|
||||
// Resolve host name and/or fill the IP address structure
|
||||
static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAddr)
|
||||
static BOOL xMBTCPPortMasterCheckHost(const CHAR *pcHostStr, ip_addr_t *pxHostAddr)
|
||||
{
|
||||
MB_PORT_CHECK((pcHostStr), FALSE, "Wrong host name or IP.");
|
||||
CHAR cStr[45];
|
||||
CHAR* pcStr = &cStr[0];
|
||||
CHAR *pcStr = &cStr[0];
|
||||
ip_addr_t xTargetAddr;
|
||||
struct addrinfo xHint;
|
||||
struct addrinfo* pxAddrList;
|
||||
struct addrinfo *pxAddrList;
|
||||
memset(&xHint, 0, sizeof(xHint));
|
||||
// Do name resolution for both protocols
|
||||
xHint.ai_family = AF_UNSPEC;
|
||||
@ -487,10 +493,10 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress)
|
||||
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR *pcIpStr, UCHAR ucSlaveAddress)
|
||||
{
|
||||
BOOL xRes = FALSE;
|
||||
MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
|
||||
MbSlaveAddrInfo_t xSlaveAddrInfo = {0};
|
||||
MB_PORT_CHECK(xMbPortConfig.xConnectQueue != NULL, FALSE, "Wrong slave IP address to add.");
|
||||
if (pcIpStr && (usIndex != 0xFF)) {
|
||||
xRes = xMBTCPPortMasterCheckHost(pcIpStr, NULL);
|
||||
@ -499,14 +505,14 @@ BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR
|
||||
xSlaveAddrInfo.pcIPAddr = pcIpStr;
|
||||
xSlaveAddrInfo.usIndex = usIndex;
|
||||
xSlaveAddrInfo.ucSlaveAddr = ucSlaveAddress;
|
||||
BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, 100);
|
||||
BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (void *)&xSlaveAddrInfo, 100);
|
||||
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "FAIL to add slave IP address: [%s].", pcIpStr);
|
||||
}
|
||||
return xRes;
|
||||
}
|
||||
|
||||
// Unblocking connect function
|
||||
static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
||||
static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t *pxInfo)
|
||||
{
|
||||
if (!pxInfo) {
|
||||
return ERR_CONN;
|
||||
@ -514,15 +520,15 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
||||
|
||||
err_t xErr = ERR_OK;
|
||||
CHAR cStr[128];
|
||||
CHAR* pcStr = NULL;
|
||||
CHAR *pcStr = NULL;
|
||||
ip_addr_t xTargetAddr;
|
||||
struct addrinfo xHint;
|
||||
struct addrinfo* pxAddrList;
|
||||
struct addrinfo* pxCurAddr;
|
||||
struct addrinfo *pxAddrList;
|
||||
struct addrinfo *pxCurAddr;
|
||||
|
||||
memset(&xHint, 0, sizeof(xHint));
|
||||
// Do name resolution for both protocols
|
||||
//xHint.ai_family = AF_UNSPEC; Todo: Find a reason why AF_UNSPEC does not work
|
||||
// xHint.ai_family = AF_UNSPEC; Todo: Find a reason why AF_UNSPEC does not work
|
||||
xHint.ai_flags = AI_ADDRCONFIG; // get IPV6 address if supported, otherwise IPV4
|
||||
xHint.ai_family = (xMbPortConfig.eMbIpVer == MB_PORT_IPV4) ? AF_INET : AF_INET6;
|
||||
xHint.ai_socktype = (pxInfo->xMbProto == MB_PROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
|
||||
@ -553,19 +559,19 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
||||
inet6_addr_to_ip6addr(ip_2_ip6(&xTargetAddr), &addr6);
|
||||
pcStr = ip6addr_ntoa_r(ip_2_ip6(&xTargetAddr), cStr, sizeof(cStr));
|
||||
// Set scope id to fix routing issues with local address
|
||||
((struct sockaddr_in6 *) (pxCurAddr->ai_addr))->sin6_scope_id =
|
||||
esp_netif_get_netif_impl_index(xMbPortConfig.pvNetIface);
|
||||
((struct sockaddr_in6 *)(pxCurAddr->ai_addr))->sin6_scope_id =
|
||||
esp_netif_get_netif_impl_index(xMbPortConfig.pvNetIface);
|
||||
}
|
||||
#endif
|
||||
if (pxInfo->xSockId <= 0) {
|
||||
pxInfo->xSockId = socket(pxCurAddr->ai_family, pxCurAddr->ai_socktype, pxCurAddr->ai_protocol);
|
||||
if (pxInfo->xSockId < 0) {
|
||||
ESP_LOGE(TAG, "Unable to create socket: #%d, errno %d", pxInfo->xSockId, errno);
|
||||
ESP_LOGE(TAG, "Unable to create socket: #%d, errno %u", (int)pxInfo->xSockId, (unsigned)errno);
|
||||
xErr = ERR_IF;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Socket (#%d)(%s) created.", pxInfo->xSockId, cStr);
|
||||
ESP_LOGV(TAG, "Socket (#%d)(%s) created.", (int)pxInfo->xSockId, cStr);
|
||||
}
|
||||
|
||||
// Set non blocking attribute for socket
|
||||
@ -576,8 +582,8 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
||||
xErr = connect(pxInfo->xSockId, (struct sockaddr*)pxCurAddr->ai_addr, pxCurAddr->ai_addrlen);
|
||||
if ((xErr < 0) && (errno == EINPROGRESS || errno == EALREADY)) {
|
||||
// The unblocking connect is pending (check status later) or already connected
|
||||
ESP_LOGV(TAG, "Socket(#%d)(%s) connection is pending, errno %d (%s).",
|
||||
pxInfo->xSockId, cStr, errno, strerror(errno));
|
||||
ESP_LOGV(TAG, "Socket(#%d)(%s) connection is pending, errno %u (%s).",
|
||||
(int)pxInfo->xSockId, cStr, (unsigned)errno, strerror(errno));
|
||||
|
||||
// Set keep alive flag in socket options
|
||||
vMBTCPPortSetKeepAlive(pxInfo);
|
||||
@ -589,13 +595,13 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
||||
continue;
|
||||
} else if (xErr != ERR_OK) {
|
||||
// Other error occurred during connection
|
||||
ESP_LOGV(TAG, MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
|
||||
pxInfo->xIndex, pxInfo->xSockId, cStr, xErr, errno, strerror(errno));
|
||||
ESP_LOGV(TAG, MB_SLAVE_FMT(" unable to connect, error=0x%x, errno %u (%s)"),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, cStr, (int)xErr, (unsigned)errno, strerror(errno));
|
||||
xMBTCPPortMasterCloseConnection(pxInfo);
|
||||
xErr = ERR_CONN;
|
||||
} else {
|
||||
ESP_LOGI(TAG, MB_SLAVE_FMT(", successfully connected."),
|
||||
pxInfo->xIndex, pxInfo->xSockId, cStr);
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, cStr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -604,9 +610,9 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
||||
}
|
||||
|
||||
// Find the first slave info whose descriptor is set in xFdSet
|
||||
static MbSlaveInfo_t* xMBTCPPortMasterGetSlaveReady(fd_set* pxFdSet)
|
||||
static MbSlaveInfo_t *xMBTCPPortMasterGetSlaveReady(fd_set *pxFdSet)
|
||||
{
|
||||
MbSlaveInfo_t* pxInfo = NULL;
|
||||
MbSlaveInfo_t *pxInfo = NULL;
|
||||
|
||||
// Slave connection loop
|
||||
for (int xIndex = 0; (xIndex < MB_TCP_PORT_MAX_CONN); xIndex++) {
|
||||
@ -619,13 +625,13 @@ static MbSlaveInfo_t* xMBTCPPortMasterGetSlaveReady(fd_set* pxFdSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
return (MbSlaveInfo_t*)NULL;
|
||||
return (MbSlaveInfo_t *)NULL;
|
||||
}
|
||||
|
||||
static int xMBTCPPortMasterCheckConnState(fd_set* pxFdSet)
|
||||
static int xMBTCPPortMasterCheckConnState(fd_set *pxFdSet)
|
||||
{
|
||||
fd_set xConnSetCheck = *pxFdSet;
|
||||
MbSlaveInfo_t* pxInfo = NULL;
|
||||
MbSlaveInfo_t *pxInfo = NULL;
|
||||
int64_t xTime = 0;
|
||||
int xErr = 0;
|
||||
int xCount = 0;
|
||||
@ -636,12 +642,12 @@ static int xMBTCPPortMasterCheckConnState(fd_set* pxFdSet)
|
||||
xErr = xMBTCPPortMasterCheckAlive(pxInfo, 0);
|
||||
if ((xErr < 0) && (((xTime - pxInfo->xRecvTimeStamp) > MB_TCP_RECONNECT_TIMEOUT) ||
|
||||
((xTime - pxInfo->xSendTimeStamp) > MB_TCP_RECONNECT_TIMEOUT))) {
|
||||
ESP_LOGI(TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%ju][%ju]."),
|
||||
pxInfo->xIndex,
|
||||
pxInfo->xSockId,
|
||||
pxInfo->pcIpAddr,
|
||||
(int64_t)(xTime - pxInfo->xRecvTimeStamp),
|
||||
(int64_t)(xTime - pxInfo->xSendTimeStamp));
|
||||
ESP_LOGI(TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%" PRIu64 "][%" PRIu64 "]."),
|
||||
(int)pxInfo->xIndex,
|
||||
(int)pxInfo->xSockId,
|
||||
pxInfo->pcIpAddr,
|
||||
(int64_t)(xTime - pxInfo->xRecvTimeStamp),
|
||||
(int64_t)(xTime - pxInfo->xSendTimeStamp));
|
||||
xCount++;
|
||||
}
|
||||
}
|
||||
@ -649,7 +655,7 @@ static int xMBTCPPortMasterCheckConnState(fd_set* pxFdSet)
|
||||
return xCount;
|
||||
}
|
||||
|
||||
static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMasterEventType xPostEvent)
|
||||
static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMasterEventEnum xPostEvent)
|
||||
{
|
||||
vMBMasterPortTimersDisable();
|
||||
vMBMasterSetErrorType(xErrType);
|
||||
@ -658,8 +664,8 @@ static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMas
|
||||
|
||||
static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
{
|
||||
MbSlaveInfo_t* pxInfo;
|
||||
MbSlaveInfo_t* pxCurrInfo;
|
||||
MbSlaveInfo_t *pxInfo;
|
||||
MbSlaveInfo_t *pxCurrInfo;
|
||||
|
||||
fd_set xConnSet;
|
||||
fd_set xReadSet;
|
||||
@ -677,23 +683,25 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
ESP_LOGE(TAG, "Fail to register slave IP.");
|
||||
} else {
|
||||
if (xSlaveAddrInfo.pcIPAddr == NULL && xMbPortConfig.usMbSlaveInfoCount && xSlaveAddrInfo.usIndex == 0xFF) {
|
||||
// Init start timeout that allows to initialize the main FSM
|
||||
xMBMasterPortEventPost(EV_MASTER_READY);
|
||||
break;
|
||||
}
|
||||
if (xMbPortConfig.usMbSlaveInfoCount > MB_TCP_PORT_MAX_CONN) {
|
||||
ESP_LOGE(TAG, "Exceeds maximum connections limit=%d.", MB_TCP_PORT_MAX_CONN);
|
||||
ESP_LOGE(TAG, "Exceeds maximum connections limit=%u.", (unsigned)MB_TCP_PORT_MAX_CONN);
|
||||
break;
|
||||
}
|
||||
pxInfo = calloc(1, sizeof(MbSlaveInfo_t));
|
||||
if (!pxInfo) {
|
||||
ESP_LOGE(TAG, "Slave(#%d), info structure allocation fail.",
|
||||
xMbPortConfig.usMbSlaveInfoCount);
|
||||
ESP_LOGE(TAG, "Slave(#%u), info structure allocation fail.",
|
||||
(unsigned)xMbPortConfig.usMbSlaveInfoCount);
|
||||
free(pxInfo);
|
||||
break;
|
||||
}
|
||||
pxInfo->pucRcvBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
|
||||
if (!pxInfo->pucRcvBuf) {
|
||||
ESP_LOGE(TAG, "Slave(#%d), receive buffer allocation fail.",
|
||||
xMbPortConfig.usMbSlaveInfoCount);
|
||||
ESP_LOGE(TAG, "Slave(#%u), receive buffer allocation fail.",
|
||||
(unsigned)xMbPortConfig.usMbSlaveInfoCount);
|
||||
free(pxInfo->pucRcvBuf);
|
||||
break;
|
||||
}
|
||||
@ -729,7 +737,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
|
||||
// if slave descriptor is NULL then it is end of list or connection closed.
|
||||
if (!pxInfo) {
|
||||
ESP_LOGV(TAG, "Index: %d is not initialized, skip.", ucCnt);
|
||||
ESP_LOGV(TAG, "Index: % is not initialized, skip.", ucCnt);
|
||||
if (xMbPortConfig.usMbSlaveInfoCount) {
|
||||
continue;
|
||||
}
|
||||
@ -744,9 +752,9 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
// In case of connection errors remove the socket from set
|
||||
if (FD_ISSET(pxInfo->xSockId, &xConnSet)) {
|
||||
FD_CLR(pxInfo->xSockId, &xConnSet);
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(" connect failed, error = %d."),
|
||||
pxInfo->xIndex, pxInfo->xSockId,
|
||||
(char*)pxInfo->pcIpAddr, xErr);
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(" connect failed, error = 0x%x."),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId,
|
||||
(char*)pxInfo->pcIpAddr, (int)xErr);
|
||||
if (usSlaveConnCnt) {
|
||||
usSlaveConnCnt--;
|
||||
}
|
||||
@ -758,20 +766,20 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
FD_SET(pxInfo->xSockId, &xConnSet);
|
||||
usSlaveConnCnt++;
|
||||
xMaxSd = (pxInfo->xSockId > xMaxSd) ? pxInfo->xSockId : xMaxSd;
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", connected %d slave(s), error = %d."),
|
||||
pxInfo->xIndex, pxInfo->xSockId,
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", connected %u slave(s), error = 0x%x."),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId,
|
||||
pxInfo->pcIpAddr,
|
||||
usSlaveConnCnt, xErr);
|
||||
(unsigned)usSlaveConnCnt, (int)xErr);
|
||||
// Update time stamp for connected slaves
|
||||
pxInfo->xRecvTimeStamp = xMBTCPGetTimeStamp();
|
||||
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", unexpected error = %d."),
|
||||
pxInfo->xIndex,
|
||||
pxInfo->xSockId,
|
||||
pxInfo->pcIpAddr, xErr);
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", unexpected error = 0x%x."),
|
||||
(int)pxInfo->xIndex,
|
||||
(int)pxInfo->xSockId,
|
||||
pxInfo->pcIpAddr, (int)xErr);
|
||||
break;
|
||||
}
|
||||
if (pxInfo) {
|
||||
@ -780,7 +788,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
xMBTCPPortMasterCheckShutdown();
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
|
||||
ESP_LOGI(TAG, "Connected %u slaves, start polling...", (unsigned)usSlaveConnCnt);
|
||||
|
||||
vMBTCPPortMasterStartPoll(); // Send event to start stack
|
||||
|
||||
@ -797,21 +805,21 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
pxCurrInfo = vMBTCPPortMasterGetCurrInfo();
|
||||
if (!pxCurrInfo) {
|
||||
ESP_LOGE(TAG, "Incorrect connection options for slave index: %d.",
|
||||
xMbPortConfig.ucCurSlaveIndex);
|
||||
(int)xMbPortConfig.ucCurSlaveIndex);
|
||||
vMBTCPPortMasterStopPoll();
|
||||
xMBTCPPortMasterCheckShutdown();
|
||||
break; // incorrect slave descriptor, reconnect.
|
||||
}
|
||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||
ESP_LOGD(TAG, "Set select timeout, left time: %ju ms.",
|
||||
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
||||
ESP_LOGD(TAG, "Set select timeout, left time: %" PRIu64 " ms.",
|
||||
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
||||
// Wait respond from current slave during respond timeout
|
||||
int xRes = vMBTCPPortMasterRxCheck(pxCurrInfo->xSockId, &xReadSet, xTime);
|
||||
if (xRes == ERR_TIMEOUT) {
|
||||
// No respond from current slave, process timeout.
|
||||
// Need to drop response later if it is received after timeout.
|
||||
ESP_LOGD(TAG, "Select timeout, left time: %ju ms.",
|
||||
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
||||
ESP_LOGD(TAG, "Select timeout, left time: %" PRIu64 " ms.",
|
||||
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||
// Wait completion of last transaction
|
||||
xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime + 1));
|
||||
@ -820,7 +828,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
} else if (xRes < 0) {
|
||||
// Select error (slave connection or r/w failure).
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", socket select error. Slave disconnected?"),
|
||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||
// Wait completion of last transaction
|
||||
xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime));
|
||||
@ -844,19 +852,20 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
// Response received correctly, send an event to stack
|
||||
xMBTCPPortMasterFsmSetError(EV_ERROR_INIT, EV_MASTER_FRAME_RECEIVED);
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame received."),
|
||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
} else if ((xRet == ERR_TIMEOUT) || (xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo) == 0)) {
|
||||
// Timeout occurred when receiving frame, process respond timeout
|
||||
xMBTCPPortMasterFsmSetError(EV_ERROR_RESPOND_TIMEOUT, EV_MASTER_ERROR_PROCESS);
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame read timeout."),
|
||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
} else if (xRet == ERR_BUF) {
|
||||
// After retries a response with incorrect TID received, process failure.
|
||||
xMBTCPPortMasterFsmSetError(EV_ERROR_RECEIVE_DATA, EV_MASTER_ERROR_PROCESS);
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame error."),
|
||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", critical error=%d."),
|
||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xRet);
|
||||
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, (int)xRet);
|
||||
// Stop polling process
|
||||
vMBTCPPortMasterStopPoll();
|
||||
xMBTCPPortMasterCheckShutdown();
|
||||
@ -865,15 +874,15 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
break;
|
||||
}
|
||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||
ESP_LOGD(TAG, "Slave #%d, data processing left time %ju [ms].", pxCurrInfo->xIndex, xTime);
|
||||
ESP_LOGD(TAG, "Slave #%d, data processing left time %" PRIu64 " [ms].", (int)pxCurrInfo->xIndex, xTime);
|
||||
// Wait completion of Modbus frame processing before start of new transaction.
|
||||
if (xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime))) {
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", data processing completed."),
|
||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||
}
|
||||
xTime = xMBTCPGetTimeStamp() - pxCurrInfo->xSendTimeStamp;
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", processing time[us] = %ju."),
|
||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", processing time[us] = %" PRIu64 "."),
|
||||
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
|
||||
}
|
||||
}
|
||||
xMBTCPPortMasterCheckShutdown();
|
||||
@ -885,14 +894,12 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
||||
extern void vMBMasterPortEventClose(void);
|
||||
extern void vMBMasterPortTimerClose(void);
|
||||
|
||||
void
|
||||
vMBMasterTCPPortEnable(void)
|
||||
void vMBMasterTCPPortEnable(void)
|
||||
{
|
||||
vTaskResume(xMbPortConfig.xMbTcpTaskHandle);
|
||||
}
|
||||
|
||||
void
|
||||
vMBMasterTCPPortDisable(void)
|
||||
void vMBMasterTCPPortDisable(void)
|
||||
{
|
||||
// Try to exit the task gracefully, so select could release its internal callbacks
|
||||
// that were allocated on the stack of the task we're going to delete
|
||||
@ -920,8 +927,7 @@ vMBMasterTCPPortDisable(void)
|
||||
free(xMbPortConfig.pxMbSlaveInfo);
|
||||
}
|
||||
|
||||
void
|
||||
vMBMasterTCPPortClose(void)
|
||||
void vMBMasterTCPPortClose(void)
|
||||
{
|
||||
vQueueDelete(xMbPortConfig.xConnectQueue);
|
||||
vMBMasterPortTimerClose();
|
||||
@ -929,10 +935,9 @@ vMBMasterTCPPortClose(void)
|
||||
vMBMasterPortEventClose();
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
|
||||
BOOL xMBMasterTCPPortGetRequest(UCHAR **ppucMBTCPFrame, USHORT *usTCPLength)
|
||||
{
|
||||
MbSlaveInfo_t* pxInfo = vMBTCPPortMasterGetCurrInfo();
|
||||
MbSlaveInfo_t *pxInfo = vMBTCPPortMasterGetCurrInfo();
|
||||
*ppucMBTCPFrame = pxInfo->pucRcvBuf;
|
||||
*usTCPLength = pxInfo->usRcvPos;
|
||||
|
||||
@ -946,51 +951,50 @@ xMBMasterTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int xMBMasterTCPPortWritePoll(MbSlaveInfo_t* pxInfo, const UCHAR * pucMBTCPFrame, USHORT usTCPLength, ULONG xTimeout)
|
||||
int xMBMasterTCPPortWritePoll(MbSlaveInfo_t *pxInfo, const UCHAR *pucMBTCPFrame, USHORT usTCPLength, ULONG xTimeout)
|
||||
{
|
||||
// Check if the socket is alive (writable and SO_ERROR == 0)
|
||||
int xRes = (int)xMBTCPPortMasterCheckAlive(pxInfo, xTimeout);
|
||||
if ((xRes < 0) && (xRes != ERR_INPROGRESS))
|
||||
{
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
|
||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
||||
if ((xRes < 0) && (xRes != ERR_INPROGRESS)) {
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %u"),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)xRes, (unsigned)errno);
|
||||
return xRes;
|
||||
}
|
||||
xRes = send(pxInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
|
||||
if (xRes < 0) {
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
|
||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data error: %d, errno %u"),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)xRes, (unsigned)errno);
|
||||
}
|
||||
return xRes;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
||||
BOOL xMBMasterTCPPortSendResponse(UCHAR *pucMBTCPFrame, USHORT usTCPLength)
|
||||
{
|
||||
BOOL bFrameSent = FALSE;
|
||||
USHORT ucCurSlaveIndex = ucMBMasterGetDestAddress();
|
||||
MbSlaveInfo_t* pxInfo = vMBTCPPortMasterFindSlaveInfo(ucCurSlaveIndex);
|
||||
MbSlaveInfo_t *pxInfo = vMBTCPPortMasterFindSlaveInfo(ucCurSlaveIndex);
|
||||
|
||||
// If the slave is correct and active then send data
|
||||
// otherwise treat slave as died and skip
|
||||
if (pxInfo != NULL) {
|
||||
if (pxInfo->xSockId < 0) {
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", send to died slave, error = %d"),
|
||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->xError);
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", send to died slave, error = %u"),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, pxInfo->pcIpAddr, (unsigned)pxInfo->xError);
|
||||
} else {
|
||||
// Apply TID field to the frame before send
|
||||
pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
|
||||
pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
|
||||
|
||||
int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
|
||||
if (xRes < 0) {
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),
|
||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
||||
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%u)."),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, pxInfo->pcIpAddr, (int)xRes, (unsigned)errno);
|
||||
bFrameSent = FALSE;
|
||||
pxInfo->xError = xRes;
|
||||
} else {
|
||||
bFrameSent = TRUE;
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", send data successful: TID=0x%02x, %d (bytes), errno %d"),
|
||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usTidCnt, xRes, errno);
|
||||
ESP_LOGD(TAG, MB_SLAVE_FMT(", send data successful: TID=0x%02x, %d (bytes), errno %u"),
|
||||
(int)pxInfo->xIndex, (int)pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usTidCnt, (int)xRes, (unsigned)errno);
|
||||
pxInfo->xError = 0;
|
||||
pxInfo->usRcvPos = 0;
|
||||
if (pxInfo->usTidCnt < (USHRT_MAX - 1)) {
|
||||
@ -1002,7 +1006,7 @@ xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
||||
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Send data to died slave, address = %d", ucCurSlaveIndex);
|
||||
ESP_LOGD(TAG, "Send data to died slave, address = %u", (unsigned)ucCurSlaveIndex);
|
||||
}
|
||||
vMBMasterPortTimersRespondTimeoutEnable();
|
||||
xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
|
||||
@ -1014,10 +1018,12 @@ BOOL MB_PORT_ISR_ATTR
|
||||
xMBMasterTCPTimerExpired(void)
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
eMBMasterTimerMode eTimerMode = xMBMasterGetCurTimerMode();
|
||||
|
||||
vMBMasterPortTimersDisable();
|
||||
|
||||
// If timer mode is respond timeout, the master event then turns EV_MASTER_EXECUTE status.
|
||||
if (xMBMasterGetCurTimerMode() == MB_TMODE_RESPOND_TIMEOUT) {
|
||||
if (eTimerMode == MB_TMODE_RESPOND_TIMEOUT) {
|
||||
vMBMasterSetErrorType(EV_ERROR_RESPOND_TIMEOUT);
|
||||
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
|
||||
}
|
||||
@ -1025,4 +1031,4 @@ xMBMasterTCPTimerExpired(void)
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
#endif //#if MB_MASTER_TCP_ENABLED
|
||||
#endif // #if MB_MASTER_TCP_ENABLED
|
||||
|
@ -54,9 +54,9 @@ static esp_err_t mbc_tcp_slave_setup(void* comm_info)
|
||||
"mb wrong communication settings.");
|
||||
mb_communication_info_t* comm_settings = (mb_communication_info_t*)comm_info;
|
||||
MB_SLAVE_CHECK((comm_settings->ip_mode == MB_MODE_TCP),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (0x%x).", (uint8_t)comm_settings->ip_mode);
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (%u).", (unsigned)comm_settings->ip_mode);
|
||||
MB_SLAVE_CHECK(((comm_settings->ip_addr_type == MB_IPV4) || (comm_settings->ip_addr_type == MB_IPV6)),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect addr type = (0x%x).", (uint8_t)comm_settings->ip_addr_type);
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect addr type = (%u).", (unsigned)comm_settings->ip_addr_type);
|
||||
MB_SLAVE_CHECK((comm_settings->ip_netif_ptr != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect iface address.");
|
||||
// Set communication options of the controller
|
||||
@ -72,9 +72,9 @@ static esp_err_t mbc_tcp_slave_start(void)
|
||||
eMBErrorCode status = MB_EIO;
|
||||
|
||||
// Initialize Modbus stack using mbcontroller parameters
|
||||
status = eMBTCPInit((USHORT)mbs_opts->mbs_comm.ip_port);
|
||||
status = eMBTCPInit((UCHAR)mbs_opts->mbs_comm.slave_uid, (USHORT)mbs_opts->mbs_comm.ip_port);
|
||||
MB_SLAVE_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack initialization failure, eMBInit() returns (0x%x).", status);
|
||||
"mb stack initialization failure, eMBInit() returns (0x%x).", (int)status);
|
||||
|
||||
eMBPortProto proto = (mbs_opts->mbs_comm.ip_mode == MB_MODE_TCP) ? MB_PROTO_TCP : MB_PROTO_UDP;
|
||||
eMBPortIpVer ip_ver = (mbs_opts->mbs_comm.ip_addr_type == MB_IPV4) ? MB_PORT_IPV4 : MB_PORT_IPV6;
|
||||
@ -82,12 +82,12 @@ static esp_err_t mbc_tcp_slave_start(void)
|
||||
|
||||
status = eMBEnable();
|
||||
MB_SLAVE_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb TCP stack start failure, eMBEnable() returned (0x%x).", (uint32_t)status);
|
||||
"mb TCP stack start failure, eMBEnable() returned (0x%x).", (int)status);
|
||||
// Set the mbcontroller start flag
|
||||
EventBits_t flag = xEventGroupSetBits(mbs_opts->mbs_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
MB_SLAVE_CHECK((flag & MB_EVENT_STACK_STARTED),
|
||||
ESP_ERR_INVALID_STATE, "mb stack start event set error.");
|
||||
ESP_ERR_INVALID_STATE, "mb stack start event set error.");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ static esp_err_t mbc_tcp_slave_destroy(void)
|
||||
EventBits_t flag = xEventGroupClearBits(mbs_opts->mbs_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
MB_SLAVE_CHECK((flag & MB_EVENT_STACK_STARTED),
|
||||
ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
|
||||
ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
|
||||
// Disable and then destroy the Modbus stack
|
||||
mb_error = eMBDisable();
|
||||
MB_SLAVE_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
|
||||
@ -132,7 +132,7 @@ static esp_err_t mbc_tcp_slave_get_param_info(mb_param_info_t* reg_info, uint32_
|
||||
mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts;
|
||||
esp_err_t err = ESP_ERR_TIMEOUT;
|
||||
MB_SLAVE_CHECK((mbs_opts->mbs_notification_queue_handle != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb queue handle is invalid.");
|
||||
ESP_ERR_INVALID_ARG, "mb queue handle is invalid.");
|
||||
MB_SLAVE_CHECK((reg_info != NULL), ESP_ERR_INVALID_ARG, "mb register information is invalid.");
|
||||
BaseType_t status = xQueueReceive(mbs_opts->mbs_notification_queue_handle,
|
||||
reg_info, pdMS_TO_TICKS(timeout));
|
||||
@ -170,13 +170,13 @@ esp_err_t mbc_tcp_slave_create(void** handler)
|
||||
// Parameter change notification queue
|
||||
mbs_opts->mbs_event_group = xEventGroupCreate();
|
||||
MB_SLAVE_CHECK((mbs_opts->mbs_event_group != NULL),
|
||||
ESP_ERR_NO_MEM, "mb event group error.");
|
||||
ESP_ERR_NO_MEM, "mb event group error.");
|
||||
// Parameter change notification queue
|
||||
mbs_opts->mbs_notification_queue_handle = xQueueCreate(
|
||||
MB_CONTROLLER_NOTIFY_QUEUE_SIZE,
|
||||
sizeof(mb_param_info_t));
|
||||
MB_SLAVE_CHECK((mbs_opts->mbs_notification_queue_handle != NULL),
|
||||
ESP_ERR_NO_MEM, "mb notify queue creation error.");
|
||||
ESP_ERR_NO_MEM, "mb notify queue creation error.");
|
||||
// Create Modbus controller task
|
||||
status = xTaskCreatePinnedToCore((void*)&modbus_tcp_slave_task,
|
||||
"modbus_tcp_slave_task",
|
||||
@ -188,8 +188,7 @@ esp_err_t mbc_tcp_slave_create(void** handler)
|
||||
if (status != pdPASS) {
|
||||
vTaskDelete(mbs_opts->mbs_task_handle);
|
||||
MB_SLAVE_CHECK((status == pdPASS), ESP_ERR_NO_MEM,
|
||||
"mb controller task creation error, xTaskCreate() returns (0x%x).",
|
||||
(uint32_t)status);
|
||||
"mb controller task creation error, xTaskCreate() returns (%u).", (unsigned)status);
|
||||
}
|
||||
|
||||
// The task is created but handle is incorrect
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
/* ----------------------- Defines -----------------------------------------*/
|
||||
#define MB_TCP_DISCONNECT_TIMEOUT ( CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000000 ) // disconnect timeout in uS
|
||||
#define MB_TCP_RESP_TIMEOUT_MS ( MB_MASTER_TIMEOUT_MS_RESPOND - 2 ) // slave response time limit
|
||||
#define MB_TCP_RESP_TIMEOUT_MS ( MB_MASTER_TIMEOUT_MS_RESPOND - 1 ) // slave response time limit
|
||||
#define MB_TCP_NET_LISTEN_BACKLOG ( SOMAXCONN )
|
||||
|
||||
/* ----------------------- Prototypes ---------------------------------------*/
|
||||
@ -106,8 +106,9 @@ static void* vxMBTCPPortRespQueueRecv(QueueHandle_t xRespQueueHandle)
|
||||
BaseType_t xStatus = xQueueReceive(xRespQueueHandle,
|
||||
(void*)&pvResp,
|
||||
pdMS_TO_TICKS(MB_TCP_RESP_TIMEOUT_MS));
|
||||
MB_PORT_CHECK((xStatus == pdTRUE), NULL, "Could not get respond confirmation.");
|
||||
MB_PORT_CHECK((pvResp), NULL, "Incorrect response processing.");
|
||||
if (xStatus != pdTRUE) {
|
||||
ESP_LOGD(TAG, "Could not get respond confirmation.");
|
||||
}
|
||||
return pvResp;
|
||||
}
|
||||
|
||||
@ -150,12 +151,13 @@ xMBTCPPortInit( USHORT usTCPPort )
|
||||
xConfig.pcBindAddr = NULL;
|
||||
|
||||
// Create task for packet processing
|
||||
BaseType_t xErr = xTaskCreate(vMBTCPPortServerTask,
|
||||
"tcp_server_task",
|
||||
BaseType_t xErr = xTaskCreatePinnedToCore(vMBTCPPortServerTask,
|
||||
"tcp_slave_task",
|
||||
MB_TCP_STACK_SIZE,
|
||||
NULL,
|
||||
MB_TCP_TASK_PRIO,
|
||||
&xConfig.xMbTcpTaskHandle);
|
||||
&xConfig.xMbTcpTaskHandle,
|
||||
MB_PORT_TASK_AFFINITY);
|
||||
vTaskSuspend(xConfig.xMbTcpTaskHandle);
|
||||
if (xErr != pdTRUE)
|
||||
{
|
||||
@ -192,7 +194,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
|
||||
// Accept new socket connection if not active
|
||||
xSockId = accept(xListenSockId, (struct sockaddr *)&xSrcAddr, &xSize);
|
||||
if (xSockId < 0) {
|
||||
ESP_LOGE(TAG, "Unable to accept connection: errno=%d", errno);
|
||||
ESP_LOGE(TAG, "Unable to accept connection: errno=%u", (unsigned)errno);
|
||||
close(xSockId);
|
||||
} else {
|
||||
// Get the sender's ip address as string
|
||||
@ -204,7 +206,11 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
|
||||
inet6_ntoa_r(((struct sockaddr_in6 *)&xSrcAddr)->sin6_addr, cAddrStr, sizeof(cAddrStr) - 1);
|
||||
}
|
||||
#endif
|
||||
ESP_LOGI(TAG, "Socket (#%d), accept client connection from address: %s", xSockId, cAddrStr);
|
||||
else {
|
||||
// Make sure ss_family is valid
|
||||
abort();
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket (#%d), accept client connection from address: %s", (int)xSockId, cAddrStr);
|
||||
pcStr = calloc(1, strlen(cAddrStr) + 1);
|
||||
if (pcStr && pcIPAddr) {
|
||||
memcpy(pcStr, cAddrStr, strlen(cAddrStr));
|
||||
@ -220,11 +226,11 @@ static BOOL xMBTCPPortCloseConnection(MbClientInfo_t* pxInfo)
|
||||
MB_PORT_CHECK(pxInfo, FALSE, "Client info is NULL.");
|
||||
|
||||
if (pxInfo->xSockId == -1) {
|
||||
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d.", pxInfo->xSockId);
|
||||
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d.", (int)pxInfo->xSockId);
|
||||
return FALSE;
|
||||
}
|
||||
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
|
||||
ESP_LOGE(TAG, "Socket (#%d), shutdown failed: errno %d", pxInfo->xSockId, errno);
|
||||
ESP_LOGE(TAG, "Socket (#%d), shutdown failed: errno %u", (int)pxInfo->xSockId, (unsigned)errno);
|
||||
}
|
||||
close(pxInfo->xSockId);
|
||||
pxInfo->xSockId = -1;
|
||||
@ -261,7 +267,7 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
|
||||
} else if (xRet == 0) {
|
||||
// timeout occurred
|
||||
if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) {
|
||||
ESP_LOGD(TAG, "Socket (#%d) Read timeout.", pxClientInfo->xSockId);
|
||||
ESP_LOGD(TAG, "Socket (#%d) Read timeout.", (int)pxClientInfo->xSockId);
|
||||
xRet = ERR_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
@ -269,20 +275,20 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
|
||||
if (FD_ISSET(pxClientInfo->xSockId, &xReadSet)) {
|
||||
// If new buffer received then read Modbus packet into buffer
|
||||
MB_PORT_CHECK((pxClientInfo->usTCPBufPos + pxClientInfo->usTCPFrameBytesLeft < MB_TCP_BUF_SIZE),
|
||||
ERR_BUF, "Socket (#%d), incorrect request buffer size = %d, ignore.",
|
||||
pxClientInfo->xSockId,
|
||||
(pxClientInfo->usTCPBufPos + pxClientInfo->usTCPFrameBytesLeft));
|
||||
ERR_BUF, "Socket (#%d), incorrect request buffer size = %u, ignore.",
|
||||
(int)pxClientInfo->xSockId,
|
||||
(unsigned)(pxClientInfo->usTCPBufPos + pxClientInfo->usTCPFrameBytesLeft));
|
||||
int xLength = recv(pxClientInfo->xSockId, &pxClientInfo->pucTCPBuf[pxClientInfo->usTCPBufPos],
|
||||
pxClientInfo->usTCPFrameBytesLeft, MSG_DONTWAIT);
|
||||
if (xLength < 0) {
|
||||
// If an error occurred during receiving
|
||||
ESP_LOGE(TAG, "Receive failed: length=%d, errno=%d", xLength, errno);
|
||||
ESP_LOGE(TAG, "Receive failed: length=%u, errno=%u", (unsigned)xLength, (unsigned)errno);
|
||||
xRet = (err_t)xLength;
|
||||
break;
|
||||
} else if (xLength == 0) {
|
||||
// Socket connection closed
|
||||
ESP_LOGD(TAG, "Socket (#%d)(%s), connection closed.",
|
||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
||||
(int)pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
||||
xRet = ERR_CLSD;
|
||||
break;
|
||||
} else {
|
||||
@ -306,7 +312,7 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
|
||||
xRet = pxClientInfo->usTCPBufPos;
|
||||
break;
|
||||
} else if ((pxClientInfo->usTCPBufPos + xLength) >= MB_TCP_BUF_SIZE) {
|
||||
ESP_LOGE(TAG, "Incorrect buffer received (%u) bytes.", xLength);
|
||||
ESP_LOGE(TAG, "Incorrect buffer received (%u) bytes.", (unsigned)xLength);
|
||||
// This should not happen. We can't deal with such a client and
|
||||
// drop the connection for security reasons.
|
||||
xRet = ERR_BUF;
|
||||
@ -391,7 +397,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
|
||||
{
|
||||
if (listen(xListenSockFd, MB_TCP_NET_LISTEN_BACKLOG) != 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error occurred during listen: errno=%d", errno);
|
||||
ESP_LOGE(TAG, "Error occurred during listen: errno=%u", (unsigned)errno);
|
||||
close(xListenSockFd);
|
||||
xListenSockFd = -1;
|
||||
continue;
|
||||
@ -399,8 +405,8 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
|
||||
}
|
||||
// Bind was successful
|
||||
pcStr = (pxCurAddr->ai_canonname == NULL) ? (CHAR*)"\0" : pxCurAddr->ai_canonname;
|
||||
ESP_LOGI(TAG, "Socket (#%d), listener %s on port: %d, errno=%d",
|
||||
xListenSockFd, pcStr, xConfig.usPort, errno);
|
||||
ESP_LOGI(TAG, "Socket (#%d), listener %s on port: %u, errno=%u",
|
||||
(int)xListenSockFd, pcStr, (unsigned)xConfig.usPort, (unsigned)errno);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -470,11 +476,11 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
// error occurred during wait for read
|
||||
ESP_LOGE(TAG, "select() errno = %d.", errno);
|
||||
ESP_LOGE(TAG, "select() errno = %u.", (unsigned)errno);
|
||||
continue;
|
||||
} else if (xErr == 0) {
|
||||
// If timeout happened, something is wrong
|
||||
ESP_LOGE(TAG, "select() timeout, errno = %d.", errno);
|
||||
ESP_LOGE(TAG, "select() timeout, errno = %u.", (unsigned)errno);
|
||||
}
|
||||
|
||||
// If something happened on the master socket, then its an incoming connection.
|
||||
@ -490,7 +496,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
||||
// if request for new connection but no space left
|
||||
if (pxClientInfo != NULL) {
|
||||
if (xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] == NULL) {
|
||||
ESP_LOGE(TAG, "Fail to accept connection %d, only %d connections supported.", i + 1, MB_TCP_PORT_MAX_CONN);
|
||||
ESP_LOGE(TAG, "Fail to accept connection %u, only %u connections supported.", (unsigned)(i + 1), (unsigned)MB_TCP_PORT_MAX_CONN);
|
||||
}
|
||||
xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] = pxClientInfo; // set last connection info
|
||||
} else {
|
||||
@ -504,7 +510,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
||||
// Accept new client connection
|
||||
pxClientInfo->xSockId = xMBTCPPortAcceptConnection(xListenSock, &pcClientIp);
|
||||
if (pxClientInfo->xSockId < 0) {
|
||||
ESP_LOGE(TAG, "Fail to accept connection for client %d.", (xConfig.usClientCount - 1));
|
||||
ESP_LOGE(TAG, "Fail to accept connection for client %u.", (unsigned)(xConfig.usClientCount - 1));
|
||||
// Accept connection fail, then free client info and continue polling.
|
||||
vMBTCPPortFreeClientInfo(pxClientInfo);
|
||||
pxClientInfo = NULL;
|
||||
@ -512,7 +518,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
||||
}
|
||||
pxClientInfo->pucTCPBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
|
||||
if (!pxClientInfo->pucTCPBuf) {
|
||||
ESP_LOGE(TAG, "Fail to allocate buffer for client %d.", (xConfig.usClientCount - 1));
|
||||
ESP_LOGE(TAG, "Fail to allocate buffer for client %u.", (unsigned)(xConfig.usClientCount - 1));
|
||||
vMBTCPPortFreeClientInfo(pxClientInfo);
|
||||
pxClientInfo = NULL;
|
||||
continue;
|
||||
@ -546,21 +552,21 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
||||
switch(xErr)
|
||||
{
|
||||
case ERR_TIMEOUT:
|
||||
ESP_LOGE(TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %d, close active connection.",
|
||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
||||
(int)(xTimeStamp - pxClientInfo->xRecvTimeStamp));
|
||||
ESP_LOGE(TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %" PRIu64 ", close active connection.",
|
||||
(int)pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
||||
(uint64_t)(xTimeStamp - pxClientInfo->xRecvTimeStamp));
|
||||
break;
|
||||
case ERR_CLSD:
|
||||
ESP_LOGE(TAG, "Socket (#%d)(%s), connection closed by peer.",
|
||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
||||
(int)pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
||||
break;
|
||||
case ERR_BUF:
|
||||
default:
|
||||
ESP_LOGE(TAG, "Socket (#%d)(%s), read data error: %d",
|
||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr, xErr);
|
||||
ESP_LOGE(TAG, "Socket (#%d)(%s), read data error: 0x%x",
|
||||
(int)pxClientInfo->xSockId, pxClientInfo->pcIpAddr, (int)xErr);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (xShutdownSemaphore) {
|
||||
xSemaphoreGive(xShutdownSemaphore);
|
||||
vTaskDelete(NULL);
|
||||
@ -588,35 +594,35 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
||||
xMBPortEventPost(EV_FRAME_RECEIVED);
|
||||
|
||||
ESP_LOGD(TAG, "Socket (#%d)(%s), get packet TID=0x%X, %d bytes.",
|
||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
||||
pxClientInfo->usTidCnt, xErr);
|
||||
(int)pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
||||
(int)pxClientInfo->usTidCnt, (int)xErr);
|
||||
|
||||
// Wait while response is not processed by stack by timeout
|
||||
UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
|
||||
if (pucSentBuffer == NULL) {
|
||||
ESP_LOGE(TAG, "Response time exceeds configured %d [ms], ignore packet.",
|
||||
MB_TCP_RESP_TIMEOUT_MS);
|
||||
ESP_LOGD(TAG, "Response is ignored, time exceeds configured %d [ms].",
|
||||
(unsigned)MB_TCP_RESP_TIMEOUT_MS);
|
||||
} else {
|
||||
USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID);
|
||||
if (usSentTid != pxClientInfo->usTidCnt) {
|
||||
ESP_LOGE(TAG, "Sent TID(%x) != Recv TID(%x), ignore packet.",
|
||||
usSentTid, pxClientInfo->usTidCnt);
|
||||
(int)usSentTid, (int)pxClientInfo->usTidCnt);
|
||||
}
|
||||
}
|
||||
|
||||
// Get time stamp of last data update
|
||||
pxClientInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
||||
ESP_LOGD(TAG, "Client %d, Socket(#%d), processing time = %d (us).",
|
||||
pxClientInfo->xIndex, pxClientInfo->xSockId,
|
||||
(int)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp));
|
||||
ESP_LOGD(TAG, "Client %d, Socket(#%d), processing time = %" PRIu64 "(us).",
|
||||
(int)pxClientInfo->xIndex, (int)pxClientInfo->xSockId,
|
||||
(uint64_t)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp));
|
||||
}
|
||||
} else {
|
||||
if (pxClientInfo) {
|
||||
// client is not ready to be read
|
||||
int64_t xTime = xMBTCPGetTimeStamp() - pxClientInfo->xRecvTimeStamp;
|
||||
if (xTime > MB_TCP_DISCONNECT_TIMEOUT) {
|
||||
ESP_LOGE(TAG, "Client %d, Socket(#%d) do not answer for %d (us). Drop connection...",
|
||||
pxClientInfo->xIndex, pxClientInfo->xSockId, (int)(xTime));
|
||||
ESP_LOGE(TAG, "Client %d, Socket(#%d) do not answer for %" PRIu64 " (us). Drop connection...",
|
||||
(int)pxClientInfo->xIndex, (int)pxClientInfo->xSockId, (uint64_t)xTime);
|
||||
xMBTCPPortCloseConnection(pxClientInfo);
|
||||
|
||||
// This client does not respond, then delete registered data
|
||||
@ -624,7 +630,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
||||
xConfig.pxMbClientInfo[i] = NULL;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Client %d is disconnected.", i);
|
||||
ESP_LOGE(TAG, "Client %d is disconnected.", (int)i);
|
||||
}
|
||||
}
|
||||
} // if ((pxClientInfo != NULL)
|
||||
@ -714,8 +720,8 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
||||
// Check if socket writable
|
||||
xErr = select(xConfig.pxCurClientInfo->xSockId + 1, NULL, &xWriteSet, &xErrorSet, &xTimeVal);
|
||||
if ((xErr == -1) || FD_ISSET(xConfig.pxCurClientInfo->xSockId, &xErrorSet)) {
|
||||
ESP_LOGE(TAG, "Socket(#%d) , send select() error = %d.",
|
||||
xConfig.pxCurClientInfo->xSockId, errno);
|
||||
ESP_LOGE(TAG, "Socket(#%d) , send select() error = %u.",
|
||||
(int)xConfig.pxCurClientInfo->xSockId, (unsigned)errno);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -726,8 +732,8 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
||||
// Write message into socket and disable Nagle's algorithm
|
||||
xErr = send(xConfig.pxCurClientInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
|
||||
if (xErr < 0) {
|
||||
ESP_LOGE(TAG, "Socket(#%d), fail to send data, errno = %d",
|
||||
xConfig.pxCurClientInfo->xSockId, errno);
|
||||
ESP_LOGE(TAG, "Socket(#%d), fail to send data, errno = %u",
|
||||
(int)xConfig.pxCurClientInfo->xSockId, (unsigned)errno);
|
||||
xConfig.pxCurClientInfo->xError = xErr;
|
||||
} else {
|
||||
bFrameSent = TRUE;
|
||||
|
@ -1,11 +1,11 @@
|
||||
version: "1.0.1"
|
||||
version: "1.0.12"
|
||||
description: ESP-MODBUS is the official Modbus library for Espressif SoCs.
|
||||
url: https://github.com/espressif/esp-modbus
|
||||
dependencies:
|
||||
idf: ">=4.1"
|
||||
idf: ">=4.3"
|
||||
files:
|
||||
exclude:
|
||||
- "docs/_build/**/*"
|
||||
- "docs/_build"
|
||||
- "test/**/build/**/*"
|
||||
- "test/**/build"
|
||||
- "docs/**/*"
|
||||
- "docs"
|
||||
- "test/**/*"
|
||||
- "test"
|
||||
|
46
pytest.ini
Normal file
46
pytest.ini
Normal file
@ -0,0 +1,46 @@
|
||||
[pytest]
|
||||
# only the files with prefix `pytest_` would be recognized as pytest test scripts.
|
||||
python_files = pytest_*.py
|
||||
|
||||
# ignore PytestExperimentalApiWarning for record_xml_attribute
|
||||
# set traceback to "short" to prevent the overwhelming tracebacks
|
||||
addopts =
|
||||
-s
|
||||
--embedded-services esp,idf
|
||||
--tb short
|
||||
--skip-check-coredump y
|
||||
|
||||
# ignore DeprecationWarning
|
||||
filterwarnings =
|
||||
ignore::DeprecationWarning:matplotlib.*:
|
||||
ignore::DeprecationWarning:google.protobuf.*:
|
||||
ignore::_pytest.warning_types.PytestExperimentalApiWarning
|
||||
|
||||
markers =
|
||||
# target markers
|
||||
esp32: support esp32 target
|
||||
esp32s2: support esp32s2 target
|
||||
esp32s3: support esp32s3 target
|
||||
esp32c3: support esp32c3 target
|
||||
esp32c2: support esp32c2 target
|
||||
|
||||
# env markers
|
||||
generic: tests should be run on generic runners
|
||||
|
||||
# multi-dut 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
|
||||
|
||||
# log related
|
||||
log_cli = True
|
||||
log_cli_level = INFO
|
||||
log_cli_format = %(asctime)s %(levelname)s %(message)s
|
||||
log_cli_date_format = %Y-%m-%d %H:%M:%S
|
||||
|
||||
# junit related
|
||||
junit_family = xunit1
|
||||
|
||||
## log all to `system-out` when case fail
|
||||
junit_logging = stdout
|
||||
junit_log_passing_tests = False
|
18
test/.build-test-rules.yml
Normal file
18
test/.build-test-rules.yml
Normal file
@ -0,0 +1,18 @@
|
||||
tcp/mb_tcp_master:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: only manual test is performed
|
||||
disable:
|
||||
- if: CONFIG_NAME == "wifi" and SOC_WIFI_SUPPORTED != 1
|
||||
|
||||
tcp/mb_tcp_slave:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: only manual test is performed
|
||||
disable:
|
||||
- if: CONFIG_NAME == "wifi" and SOC_WIFI_SUPPORTED != 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
319
test/conftest.py
Normal file
319
test/conftest.py
Normal file
@ -0,0 +1,319 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# pylint: disable=W0621 # redefined-outer-name
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Dict, Match, Optional, TextIO, Tuple
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from pytest_embedded.plugin import multi_dut_argument, multi_dut_fixture
|
||||
from pytest_embedded_idf.app import IdfApp
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
from pytest_embedded_idf.serial import IdfSerial
|
||||
|
||||
|
||||
class Stages(Enum):
|
||||
STACK_DEFAULT = 1
|
||||
STACK_IPV4 = 2
|
||||
STACK_IPV6 = 3
|
||||
STACK_INIT = 4
|
||||
STACK_CONNECT = 5
|
||||
STACK_START = 6
|
||||
STACK_PAR_OK = 7
|
||||
STACK_PAR_FAIL = 8
|
||||
STACK_DESTROY = 9
|
||||
|
||||
DEFAULT_SDKCONFIG = 'default'
|
||||
ALLOWED_PERCENT_OF_FAILS = 10
|
||||
|
||||
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_EXPECT_STR_TIMEOUT = 120
|
||||
TEST_ACK_TIMEOUT = 60
|
||||
TEST_MAX_CIDS = 8
|
||||
|
||||
app: IdfApp
|
||||
serial: IdfSerial
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None: # type: ignore
|
||||
super().__init__(*args, **kwargs)
|
||||
self.logger = logging.getLogger()
|
||||
self.test_output: Optional[TextIO] = None
|
||||
self.ip_address: Optional[str] = None
|
||||
self.app_name: Optional[str] = None
|
||||
self.param_fail_count = 0
|
||||
self.param_ok_count = 0
|
||||
self.test_stage = Stages.STACK_DEFAULT
|
||||
self.dictionary = None
|
||||
self.test_finish = False
|
||||
self.test_status = False
|
||||
|
||||
def close(self) -> None:
|
||||
super().close()
|
||||
|
||||
def dut_get_ip(self) -> Optional[str]:
|
||||
if self.ip_address is None:
|
||||
expect_address = self.expect(self.TEST_IP_ADDRESS_REGEXP, timeout=self.TEST_EXPECT_STR_TIMEOUT)
|
||||
if isinstance(expect_address, Match):
|
||||
self.ip_address = expect_address.group(1).decode('ascii')
|
||||
return self.ip_address
|
||||
|
||||
def dut_get_name(self) -> Optional[str]:
|
||||
if self.app_name is None:
|
||||
expect_name = self.expect(self.TEST_APP_NAME, timeout=self.TEST_EXPECT_STR_TIMEOUT)
|
||||
if isinstance(expect_name, Match):
|
||||
self.app_name = expect_name.group(1).decode('ascii')
|
||||
return self.app_name
|
||||
|
||||
def dut_send_ip(self, slave_ip: Optional[str]) -> Optional[int]:
|
||||
''' The function sends the slave IP address defined as a parameter to master
|
||||
'''
|
||||
addr_num = 0
|
||||
self.expect(self.TEST_IP_PROMPT, timeout=self.TEST_ACK_TIMEOUT)
|
||||
if isinstance(slave_ip, str):
|
||||
for addr_num in range(0, self.TEST_MAX_CIDS):
|
||||
message = r'IP{}={}'.format(addr_num, slave_ip)
|
||||
self.logger.info('{} sent to master'.format(message))
|
||||
self.write(message)
|
||||
return addr_num
|
||||
|
||||
def get_expect_proc(self) -> Optional[object]:
|
||||
expect_proc: object = None
|
||||
try:
|
||||
expect_proc = self.__getattribute__('pexpect_proc')
|
||||
except:
|
||||
expect_proc = self.__getattribute__('_p')
|
||||
finally:
|
||||
if (expect_proc and callable(getattr(expect_proc, 'expect'))):
|
||||
return expect_proc
|
||||
else :
|
||||
return None
|
||||
|
||||
def expect_any(self, *expect_items: Tuple[str, Callable], timeout: Optional[int]) -> None:
|
||||
"""
|
||||
expect_any(*expect_items, timeout=DEFAULT_TIMEOUT)
|
||||
expect any of the patterns.
|
||||
will call callback (if provided) if pattern match succeed and then return.
|
||||
will pass match result to the callback.
|
||||
|
||||
:raise ExpectTimeout: failed to match any one of the expect items before timeout
|
||||
:raise UnsupportedExpectItem: pattern in expect_item is not string or compiled RegEx
|
||||
|
||||
:arg expect_items: one or more expect items.
|
||||
string, compiled RegEx pattern or (string or RegEx(string pattern), callback)
|
||||
:keyword timeout: timeout for expect
|
||||
:return: matched item
|
||||
"""
|
||||
def process_expected_item(item_raw: Tuple[str, Callable[..., Any]]) -> Dict[str, Any]:
|
||||
# convert item raw data to standard dict
|
||||
item = {
|
||||
'pattern': item_raw[0] if isinstance(item_raw, tuple) else item_raw,
|
||||
'callback': item_raw[1] if isinstance(item_raw, tuple) else None,
|
||||
'index': -1,
|
||||
'ret': None,
|
||||
}
|
||||
return item
|
||||
|
||||
expect_items_list = [process_expected_item(item) for item in expect_items]
|
||||
expect_patterns = [item['pattern'] for item in expect_items_list if item['pattern'] is not None]
|
||||
match_item = None
|
||||
|
||||
# Workaround: We need to use the original expect method of pexpect process which returns
|
||||
# index of matched pattern instead of Match object returned by dut.expect()
|
||||
expect_proc: Optional[object] = self.get_expect_proc()
|
||||
|
||||
if expect_proc is not None:
|
||||
match_index = expect_proc.expect(expect_patterns, timeout)
|
||||
|
||||
if isinstance(match_index, int):
|
||||
match_item = expect_items_list[match_index] # type: ignore
|
||||
match_item['index'] = match_index # type: ignore , keep match index
|
||||
if isinstance(expect_proc.match, Match) and len(expect_proc.match.groups()) > 0:
|
||||
match_item['ret'] = expect_proc.match.groups()
|
||||
if match_item['callback']:
|
||||
match_item['callback'](match_item['ret']) # execution of callback function
|
||||
else:
|
||||
self.logger.error('%s: failed to parse output. Please check component versions.', self.app_name)
|
||||
raise RuntimeError from None
|
||||
|
||||
def dut_test_start(self, dictionary: Dict, timeout_value=TEST_EXPECT_STR_TIMEOUT) -> None: # type: ignore
|
||||
""" The method to initialize and handle test stages
|
||||
"""
|
||||
def handle_get_ip4(data: Optional[Any]) -> None:
|
||||
""" Handle get_ip v4
|
||||
"""
|
||||
self.logger.info('%s[STACK_IPV4]: %s', self.app_name, str(data))
|
||||
self.test_stage = Stages.STACK_IPV4
|
||||
|
||||
def handle_get_ip6(data: Optional[Any]) -> None:
|
||||
""" Handle get_ip v6
|
||||
"""
|
||||
self.logger.info('%s[STACK_IPV6]: %s', self.app_name, str(data))
|
||||
self.test_stage = Stages.STACK_IPV6
|
||||
|
||||
def handle_init(data: Optional[Any]) -> None:
|
||||
""" Handle init
|
||||
"""
|
||||
self.logger.info('%s[STACK_INIT]: %s', self.app_name, str(data))
|
||||
self.test_stage = Stages.STACK_INIT
|
||||
|
||||
def handle_connect(data: Optional[Any]) -> None:
|
||||
""" Handle connect
|
||||
"""
|
||||
self.logger.info('%s[STACK_CONNECT]: %s', self.app_name, str(data))
|
||||
self.test_stage = Stages.STACK_CONNECT
|
||||
|
||||
def handle_test_start(data: Optional[Any]) -> None:
|
||||
""" Handle connect
|
||||
"""
|
||||
self.logger.info('%s[STACK_START]: %s', self.app_name, str(data))
|
||||
self.test_stage = Stages.STACK_START
|
||||
|
||||
def handle_par_ok(data: Optional[Any]) -> None:
|
||||
""" Handle parameter ok
|
||||
"""
|
||||
self.logger.info('%s[READ_PAR_OK]: %s', self.app_name, str(data))
|
||||
if self.test_stage.value >= Stages.STACK_START.value:
|
||||
self.param_ok_count += 1
|
||||
self.test_stage = Stages.STACK_PAR_OK
|
||||
|
||||
def handle_par_fail(data: Optional[Any]) -> None:
|
||||
""" Handle parameter fail
|
||||
"""
|
||||
self.logger.info('%s[READ_PAR_FAIL]: %s', self.app_name, str(data))
|
||||
self.param_fail_count += 1
|
||||
self.test_stage = Stages.STACK_PAR_FAIL
|
||||
|
||||
def handle_destroy(data: Optional[Any]) -> None:
|
||||
""" Handle destroy
|
||||
"""
|
||||
self.logger.info('%s[%s]: %s', self.app_name, Stages.STACK_DESTROY.name, str(data))
|
||||
self.test_stage = Stages.STACK_DESTROY
|
||||
self.test_finish = True
|
||||
|
||||
while not self.test_finish:
|
||||
try:
|
||||
self.expect_any((dictionary[Stages.STACK_IPV4], handle_get_ip4),
|
||||
(dictionary[Stages.STACK_IPV6], handle_get_ip6),
|
||||
(dictionary[Stages.STACK_INIT], handle_init),
|
||||
(dictionary[Stages.STACK_CONNECT], handle_connect),
|
||||
(dictionary[Stages.STACK_START], handle_test_start),
|
||||
(dictionary[Stages.STACK_PAR_OK], handle_par_ok),
|
||||
(dictionary[Stages.STACK_PAR_FAIL], handle_par_fail),
|
||||
(dictionary[Stages.STACK_DESTROY], handle_destroy),
|
||||
timeout=timeout_value)
|
||||
except pexpect.TIMEOUT:
|
||||
self.logger.info('%s, expect timeout on stage %s (%s seconds)', self.app_name, self.test_stage.name, timeout_value)
|
||||
self.test_finish = True
|
||||
|
||||
def dut_check_errors(self) -> None:
|
||||
''' Verify allowed percentage of errors for the dut
|
||||
'''
|
||||
allowed_ok_percentage = ((self.param_ok_count / (self.param_ok_count + self.param_fail_count + 1)) * 100)
|
||||
if self.param_ok_count and (allowed_ok_percentage > (100 - ALLOWED_PERCENT_OF_FAILS)):
|
||||
self.logger.info('%s: ok_count: %d, fail count: %d', self.app_name, self.param_ok_count, self.param_fail_count)
|
||||
else :
|
||||
self.logger.error('%s: ok_count: %d, number of failed readings %d exceeds %d percent', self.app_name, self.param_ok_count, self.param_fail_count, ALLOWED_PERCENT_OF_FAILS)
|
||||
raise RuntimeError from None
|
||||
|
||||
############
|
||||
# Fixtures #
|
||||
############
|
||||
|
||||
@pytest.fixture(scope='session', autouse=True)
|
||||
def session_tempdir() -> str:
|
||||
|
||||
_tmpdir = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'pytest_embedded_log',
|
||||
datetime.now().strftime('%Y-%m-%d_%H-%M-%S'),
|
||||
)
|
||||
os.makedirs(_tmpdir, exist_ok=True)
|
||||
return _tmpdir
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@multi_dut_fixture
|
||||
def junit_properties(
|
||||
test_case_name: str, record_xml_attribute: Callable[[str, object], None]
|
||||
) -> None:
|
||||
"""
|
||||
This fixture is autoused and will modify the junit report test case name to <target>.<config>.<case_name>
|
||||
"""
|
||||
record_xml_attribute('name', test_case_name)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch:
|
||||
mp = MonkeyPatch()
|
||||
request.addfinalizer(mp.undo)
|
||||
return mp
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', autouse=True)
|
||||
def replace_dut_class(monkeypatch_module: MonkeyPatch) -> None:
|
||||
monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', ModbusTestDut)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@multi_dut_argument
|
||||
def config(request: FixtureRequest) -> str:
|
||||
return getattr(request, 'param', None) or DEFAULT_SDKCONFIG
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@multi_dut_fixture
|
||||
def build_dir(app_path: str, target: Optional[str], config: Optional[str]) -> str:
|
||||
"""
|
||||
Check local build dir with the following priority:
|
||||
|
||||
1. build_<target>_<config>
|
||||
2. build_<target>
|
||||
3. build_<config>
|
||||
4. build
|
||||
|
||||
Args:
|
||||
app_path: app path
|
||||
target: target
|
||||
config: config
|
||||
|
||||
Returns:
|
||||
valid build directory
|
||||
"""
|
||||
check_dirs = []
|
||||
if target is not None and config is not None:
|
||||
check_dirs.append(f'build_{target}_{config}')
|
||||
if target is not None:
|
||||
check_dirs.append(f'build_{target}')
|
||||
if config is not None:
|
||||
check_dirs.append(f'build_{config}')
|
||||
check_dirs.append('build')
|
||||
|
||||
for check_dir in check_dirs:
|
||||
binary_path = os.path.join(app_path, check_dir)
|
||||
if os.path.isdir(binary_path):
|
||||
logging.info(f'find valid binary path: {binary_path}')
|
||||
return check_dir
|
||||
|
||||
logging.warning(
|
||||
'checking binary path: %s... missing... try another place', binary_path
|
||||
)
|
||||
|
||||
recommend_place = check_dirs[0]
|
||||
logging.error(
|
||||
f'no build dir valid. Please build the binary via "idf.py -B {recommend_place} build" and run pytest again'
|
||||
)
|
||||
sys.exit(1)
|
@ -3,3 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
idf_component_register(SRCS "modbus_params.c"
|
||||
INCLUDE_DIRS "include")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -3,7 +3,7 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../../")
|
||||
set(EXCLUDE_COMPONENTS examples test_app test freemodbus)
|
||||
set(EXCLUDE_COMPONENTS freemodbus)
|
||||
|
||||
# Include parameters from common modbus folder
|
||||
set(MB_PARAMS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../mb_example_common")
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Modbus Master Example
|
||||
|
||||
@ -72,7 +72,7 @@ RS485 example circuit schematic for connection of master and slave devices into
|
||||
+-------x-------+ +-------x-------+
|
||||
RXD <------| RO | DIFFERENTIAL | RO|-----> RXD
|
||||
| B|---------------|B |
|
||||
TXD ------>| DI MAX485 | \ / | MAX485 DI|<----- TXD
|
||||
TXD ------>| DI MAX483 | \ / | MAX483 DI|<----- TXD
|
||||
ESP32 BOARD | | RS-485 side | | External PC (emulator) with USB to serial or
|
||||
RTS --+--->| DE | / \ | DE|---+ ESP32 BOARD (slave)
|
||||
| | A|---------------|A | |
|
||||
@ -95,15 +95,15 @@ Configure the UART pins used for modbus communication using and table below.
|
||||
Define the communication mode parameter for master and slave in Kconfig - CONFIG_MB_COMM_MODE (must be the same for master and slave devices in one segment).
|
||||
Configure the slave address for each slave in the Modbus segment (the CONFIG_MB_SLAVE_ADDR in Kconfig).
|
||||
```
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
| UART Interface | #define | Default ESP32 Pin | Default pins for | External RS485 Driver Pin |
|
||||
| | | | ESP32-S2(S3, C3) | |
|
||||
| ----------------------|--------------------|-----------------------|-----------------------|---------------------------|
|
||||
| Transmit Data (TxD) | CONFIG_MB_UART_TXD | GPIO23 | GPIO9 | DI |
|
||||
| Receive Data (RxD) | CONFIG_MB_UART_RXD | GPIO22 | GPIO8 | RO |
|
||||
| Request To Send (RTS) | CONFIG_MB_UART_RTS | GPIO18 | GPIO10 | ~RE/DE |
|
||||
| Ground | n/a | GND | GND | GND |
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------------------------
|
||||
| UART Interface | #define | Default pins for | Default pins for | External RS485 Driver Pin |
|
||||
| | | ESP32 (C6) | ESP32-S2 (S3, C3, C2, H2) | |
|
||||
| ----------------------|--------------------|-----------------------|---------------------------|---------------------------|
|
||||
| Transmit Data (TxD) | CONFIG_MB_UART_TXD | GPIO23 | GPIO9 | DI |
|
||||
| Receive Data (RxD) | CONFIG_MB_UART_RXD | GPIO22 | GPIO8 | RO |
|
||||
| Request To Send (RTS) | CONFIG_MB_UART_RTS | GPIO18 | GPIO10 | ~RE/DE |
|
||||
| Ground | n/a | GND | GND | GND |
|
||||
------------------------------------------------------------------------------------------------------------------------------
|
||||
```
|
||||
Note: Each target chip has different GPIO pins available for UART connection. Please refer to UART documentation for selected target for more information.
|
||||
|
||||
|
@ -1,11 +1,21 @@
|
||||
menu "Modbus Example Configuration"
|
||||
|
||||
config MB_UART_PORT_ONE
|
||||
bool
|
||||
default y
|
||||
depends on (ESP_CONSOLE_UART_NUM !=1) && (SOC_UART_NUM > 1)
|
||||
|
||||
config MB_UART_PORT_TWO
|
||||
bool
|
||||
default y
|
||||
depends on (ESP_CONSOLE_UART_NUM !=2) && (SOC_UART_NUM > 2)
|
||||
|
||||
config MB_UART_PORT_NUM
|
||||
int "UART port number"
|
||||
range 0 2 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
|
||||
default 2 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
|
||||
range 0 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
|
||||
default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
|
||||
range 0 2 if MB_UART_PORT_TWO
|
||||
default 2 if MB_UART_PORT_TWO
|
||||
range 0 1 if MB_UART_PORT_ONE
|
||||
default 1 if MB_UART_PORT_ONE
|
||||
help
|
||||
UART communication port number for Modbus example.
|
||||
|
||||
@ -19,11 +29,15 @@ menu "Modbus Example Configuration"
|
||||
config MB_UART_RXD
|
||||
int "UART RXD pin number"
|
||||
range 0 34 if IDF_TARGET_ESP32
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
range 0 23 if IDF_TARGET_ESP32C6
|
||||
default 22 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
|
||||
range 0 46 if IDF_TARGET_ESP32S2
|
||||
range 0 47 if IDF_TARGET_ESP32S3
|
||||
range 0 19 if IDF_TARGET_ESP32C3
|
||||
default 8 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
range 0 20 if IDF_TARGET_ESP32C2
|
||||
range 0 27 if IDF_TARGET_ESP32H2
|
||||
default 8 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
|
||||
help
|
||||
GPIO number for UART RX pin. See UART documentation for more information
|
||||
about available pin numbers for UART.
|
||||
@ -31,11 +45,15 @@ menu "Modbus Example Configuration"
|
||||
config MB_UART_TXD
|
||||
int "UART TXD pin number"
|
||||
range 0 34 if IDF_TARGET_ESP32
|
||||
default 23 if IDF_TARGET_ESP32
|
||||
range 0 23 if IDF_TARGET_ESP32C6
|
||||
default 23 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
|
||||
range 0 46 if IDF_TARGET_ESP32S2
|
||||
range 0 47 if IDF_TARGET_ESP32S3
|
||||
range 0 19 if IDF_TARGET_ESP32C3
|
||||
default 9 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
range 0 20 if IDF_TARGET_ESP32C2
|
||||
range 0 27 if IDF_TARGET_ESP32H2
|
||||
default 9 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 9 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
|
||||
help
|
||||
GPIO number for UART TX pin. See UART documentation for more information
|
||||
about available pin numbers for UART.
|
||||
@ -43,11 +61,15 @@ menu "Modbus Example Configuration"
|
||||
config MB_UART_RTS
|
||||
int "UART RTS pin number"
|
||||
range 0 34 if IDF_TARGET_ESP32
|
||||
default 18 if IDF_TARGET_ESP32
|
||||
range 0 23 if IDF_TARGET_ESP32C6
|
||||
default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
|
||||
range 0 46 if IDF_TARGET_ESP32S2
|
||||
range 0 47 if IDF_TARGET_ESP32S3
|
||||
range 0 19 if IDF_TARGET_ESP32C3
|
||||
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
range 0 20 if IDF_TARGET_ESP32C2
|
||||
range 0 27 if IDF_TARGET_ESP32H2
|
||||
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 10 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
|
||||
help
|
||||
GPIO number for UART RTS pin. This pin is connected to
|
||||
~RE/DE pin of RS485 transceiver to switch direction.
|
||||
|
@ -121,7 +121,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", (int)param_descriptor->cid);
|
||||
assert(instance_ptr != NULL);
|
||||
}
|
||||
return instance_ptr;
|
||||
@ -155,11 +155,11 @@ static void master_operation_func(void *arg)
|
||||
err = mbc_master_get_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%08x) read successful.",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
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);
|
||||
@ -167,14 +167,14 @@ static void master_operation_func(void *arg)
|
||||
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%08x), write successful.",
|
||||
param_descriptor->cid,
|
||||
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).",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
@ -182,7 +182,7 @@ static void master_operation_func(void *arg)
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
@ -194,8 +194,8 @@ static void master_operation_func(void *arg)
|
||||
*(float*)temp_data_ptr = value;
|
||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
|
||||
param_descriptor->cid,
|
||||
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,
|
||||
@ -209,7 +209,7 @@ static void master_operation_func(void *arg)
|
||||
uint16_t state = *(uint16_t*)temp_data_ptr;
|
||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
(const char*)rw_str,
|
||||
@ -221,7 +221,7 @@ static void master_operation_func(void *arg)
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
@ -235,7 +235,7 @@ static void master_operation_func(void *arg)
|
||||
|
||||
if (alarm_state) {
|
||||
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
|
||||
param_descriptor->cid);
|
||||
(int)param_descriptor->cid);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
|
||||
MASTER_MAX_RETRY);
|
||||
@ -264,12 +264,10 @@ static esp_err_t master_init(void)
|
||||
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail.");
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
"mb controller initialization fail, returns(0x%x).", (int)err);
|
||||
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).",
|
||||
(uint32_t)err);
|
||||
"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,
|
||||
@ -277,21 +275,19 @@ static esp_err_t master_init(void)
|
||||
|
||||
err = mbc_master_start();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller start fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
"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).", (uint32_t)err);
|
||||
"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,
|
||||
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err);
|
||||
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err);
|
||||
|
||||
vTaskDelay(5);
|
||||
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller set descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
"mb controller set descriptor fail, returns(0x%x).", (int16_t)err);
|
||||
ESP_LOGI(TAG, "Modbus master stack initialized...");
|
||||
return err;
|
||||
}
|
||||
|
5
test/serial/mb_serial_master/sdkconfig.ci.ascii
Normal file
5
test/serial/mb_serial_master/sdkconfig.ci.ascii
Normal file
@ -0,0 +1,5 @@
|
||||
CONFIG_MB_COMM_MODE_ASCII=y
|
||||
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
|
6
test/serial/mb_serial_master/sdkconfig.ci.rtu
Normal file
6
test/serial/mb_serial_master/sdkconfig.ci.rtu
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_MB_COMM_MODE_ASCII=n
|
||||
CONFIG_MB_COMM_MODE_RTU=y
|
||||
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
|
@ -3,8 +3,6 @@
|
||||
#
|
||||
CONFIG_MB_COMM_MODE_ASCII=y
|
||||
CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_TIMER_PORT_ENABLED=n
|
||||
CONFIG_FMB_TIMER_ISR_IN_IRAM=y
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=400
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Modbus Slave Example
|
||||
|
||||
@ -25,7 +25,7 @@ RS485 example circuit schematic:
|
||||
+-------x-------+ +-------x-------+
|
||||
RXD <------| RO | DIFFERENTIAL | RO|-----> RXD
|
||||
| B|---------------|B |
|
||||
TXD ------>| DI MAX485 | \ / | MAX485 DI|<----- TXD
|
||||
TXD ------>| DI MAX483 | \ / | MAX483 DI|<----- TXD
|
||||
ESP32 board | | RS-485 side | | Modbus master
|
||||
RTS --+--->| DE | / \ | DE|---+
|
||||
| | A|---------------|A | |
|
||||
@ -45,15 +45,15 @@ idf.py menuconfig
|
||||
Select Modbus Example Configuration menu item.
|
||||
Configure the UART pins used for modbus communication using the command and table below.
|
||||
```
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
| UART Interface | #define | Default ESP32 Pin | Default pins for | External RS485 Driver Pin |
|
||||
| | | | ESP32-S2(S3, C3) | |
|
||||
| ----------------------|--------------------|-----------------------|-----------------------|---------------------------|
|
||||
| Transmit Data (TxD) | CONFIG_MB_UART_TXD | GPIO23 | GPIO9 | DI |
|
||||
| Receive Data (RxD) | CONFIG_MB_UART_RXD | GPIO22 | GPIO8 | RO |
|
||||
| Request To Send (RTS) | CONFIG_MB_UART_RTS | GPIO18 | GPIO10 | ~RE/DE |
|
||||
| Ground | n/a | GND | GND | GND |
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------------------------
|
||||
| UART Interface | #define | Default pins for | Default pins for | External RS485 Driver Pin |
|
||||
| | | ESP32 (C6) | ESP32-S2 (S3, C3, C2, H2) | |
|
||||
| ----------------------|--------------------|-----------------------|---------------------------|---------------------------|
|
||||
| Transmit Data (TxD) | CONFIG_MB_UART_TXD | GPIO23 | GPIO9 | DI |
|
||||
| Receive Data (RxD) | CONFIG_MB_UART_RXD | GPIO22 | GPIO8 | RO |
|
||||
| Request To Send (RTS) | CONFIG_MB_UART_RTS | GPIO18 | GPIO10 | ~RE/DE |
|
||||
| Ground | n/a | GND | GND | GND |
|
||||
------------------------------------------------------------------------------------------------------------------------------
|
||||
```
|
||||
Note: Each target chip has different GPIO pins available for UART connection. Please refer to UART documentation for selected target for more information.
|
||||
|
||||
|
@ -2,3 +2,4 @@ set(PROJECT_NAME "modbus_slave")
|
||||
|
||||
idf_component_register(SRCS "slave.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
|
@ -1,11 +1,21 @@
|
||||
menu "Modbus Example Configuration"
|
||||
|
||||
config MB_UART_PORT_ONE
|
||||
bool
|
||||
default y
|
||||
depends on (ESP_CONSOLE_UART_NUM !=1) && (SOC_UART_NUM > 1)
|
||||
|
||||
config MB_UART_PORT_TWO
|
||||
bool
|
||||
default y
|
||||
depends on (ESP_CONSOLE_UART_NUM !=2) && (SOC_UART_NUM > 2)
|
||||
|
||||
config MB_UART_PORT_NUM
|
||||
int "UART port number"
|
||||
range 0 2 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
|
||||
default 2 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
|
||||
range 0 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
|
||||
default 1 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
|
||||
range 0 2 if MB_UART_PORT_TWO
|
||||
default 2 if MB_UART_PORT_TWO
|
||||
range 0 1 if MB_UART_PORT_ONE
|
||||
default 1 if MB_UART_PORT_ONE
|
||||
help
|
||||
UART communication port number for Modbus example.
|
||||
|
||||
@ -19,11 +29,15 @@ menu "Modbus Example Configuration"
|
||||
config MB_UART_RXD
|
||||
int "UART RXD pin number"
|
||||
range 0 34 if IDF_TARGET_ESP32
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
range 0 23 if IDF_TARGET_ESP32C6
|
||||
default 22 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
|
||||
range 0 46 if IDF_TARGET_ESP32S2
|
||||
range 0 47 if IDF_TARGET_ESP32S3
|
||||
range 0 19 if IDF_TARGET_ESP32C3
|
||||
default 8 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
range 0 20 if IDF_TARGET_ESP32C2
|
||||
range 0 27 if IDF_TARGET_ESP32H2
|
||||
default 8 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
|
||||
help
|
||||
GPIO number for UART RX pin. See UART documentation for more information
|
||||
about available pin numbers for UART.
|
||||
@ -31,11 +45,15 @@ menu "Modbus Example Configuration"
|
||||
config MB_UART_TXD
|
||||
int "UART TXD pin number"
|
||||
range 0 34 if IDF_TARGET_ESP32
|
||||
default 23 if IDF_TARGET_ESP32
|
||||
range 0 23 if IDF_TARGET_ESP32C6
|
||||
default 23 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
|
||||
range 0 46 if IDF_TARGET_ESP32S2
|
||||
range 0 47 if IDF_TARGET_ESP32S3
|
||||
range 0 19 if IDF_TARGET_ESP32C3
|
||||
default 9 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
range 0 20 if IDF_TARGET_ESP32C2
|
||||
range 0 27 if IDF_TARGET_ESP32H2
|
||||
default 9 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 9 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
|
||||
help
|
||||
GPIO number for UART TX pin. See UART documentation for more information
|
||||
about available pin numbers for UART.
|
||||
@ -43,11 +61,15 @@ menu "Modbus Example Configuration"
|
||||
config MB_UART_RTS
|
||||
int "UART RTS pin number"
|
||||
range 0 34 if IDF_TARGET_ESP32
|
||||
default 18 if IDF_TARGET_ESP32
|
||||
range 0 23 if IDF_TARGET_ESP32C6
|
||||
default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
|
||||
range 0 46 if IDF_TARGET_ESP32S2
|
||||
range 0 47 if IDF_TARGET_ESP32S3
|
||||
range 0 19 if IDF_TARGET_ESP32C3
|
||||
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
range 0 20 if IDF_TARGET_ESP32C2
|
||||
range 0 27 if IDF_TARGET_ESP32H2
|
||||
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 10 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
|
||||
help
|
||||
GPIO number for UART RTS pin. This pin is connected to
|
||||
~RE/DE pin of RS485 transceiver to switch direction.
|
||||
|
@ -182,13 +182,13 @@ void app_main(void)
|
||||
if(event & (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",
|
||||
ESP_LOGI(TAG, "HOLDING %s (%" PRIu32 " us), ADDR:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 ", SIZE:%u",
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(uint32_t)reg_info.size);
|
||||
(unsigned)reg_info.size);
|
||||
if (reg_info.address == (uint8_t*)&holding_reg_params.holding_data0)
|
||||
{
|
||||
portENTER_CRITICAL(¶m_lock);
|
||||
@ -200,29 +200,29 @@ void app_main(void)
|
||||
}
|
||||
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
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,
|
||||
(uint32_t)reg_info.size);
|
||||
(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));
|
||||
ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
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,
|
||||
(uint32_t)reg_info.size);
|
||||
(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));
|
||||
ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
ESP_LOGI(TAG, "COILS %s (%" PRIu32 " us), ADDR:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 ", SIZE:%u",
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(uint32_t)reg_info.size);
|
||||
(unsigned)reg_info.size);
|
||||
if (coil_reg_params.coils_port1 == 0xFF) break;
|
||||
}
|
||||
}
|
||||
|
4
test/serial/mb_serial_slave/sdkconfig.ci.ascii
Normal file
4
test/serial/mb_serial_slave/sdkconfig.ci.ascii
Normal file
@ -0,0 +1,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
|
5
test/serial/mb_serial_slave/sdkconfig.ci.rtu
Normal file
5
test/serial/mb_serial_slave/sdkconfig.ci.rtu
Normal file
@ -0,0 +1,5 @@
|
||||
CONFIG_MB_COMM_MODE_ASCII=n
|
||||
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
|
@ -4,6 +4,4 @@
|
||||
CONFIG_MB_COMM_MODE_ASCII=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_MB_UART_BAUD_RATE=115200
|
||||
CONFIG_FMB_TIMER_PORT_ENABLED=n
|
||||
CONFIG_FMB_TIMER_ISR_IN_IRAM=y
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
|
66
test/serial/pytest_mb_master_slave.py
Normal file
66
test/serial/pytest_mb_master_slave.py
Normal file
@ -0,0 +1,66 @@
|
||||
# SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# This is the script to reproduce the issue when the expect() is called from
|
||||
# main thread in Multi DUT case.
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from conftest import ModbusTestDut, Stages
|
||||
|
||||
pattern_dict_slave = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_connect: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||
Stages.STACK_IPV6: (r'I \([0-9]+\) example_connect: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
||||
Stages.STACK_INIT: (r'I \(([0-9]+)\) MB_TCP_SLAVE_PORT: (Protocol stack initialized).'),
|
||||
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) MB_TCP_SLAVE_PORT: Socket \(#[0-9]+\), accept client connection from address: '
|
||||
r'([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||
Stages.STACK_START: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Start modbus test)'),
|
||||
Stages.STACK_PAR_OK: (r'I\s\(([0-9]+)\) SLAVE_TEST: ([A-Z]+ [A-Z]+) \([a-zA-Z0-9_]+ us\),\s'
|
||||
r'ADDR:([0-9]+), TYPE:[0-9]+, INST_ADDR:0x[a-zA-Z0-9]+, SIZE:[0-9]+'),
|
||||
Stages.STACK_PAR_FAIL: (r'E \(([0-9]+)\) SLAVE_TEST: Response time exceeds configured [0-9]+ [ms], ignore packet'),
|
||||
Stages.STACK_DESTROY: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Modbus controller destroyed).')}
|
||||
|
||||
pattern_dict_master = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_connect: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||
Stages.STACK_IPV6: (r'I \([0-9]+\) example_connect: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
||||
Stages.STACK_INIT: (r'I \(([0-9]+)\) MASTER_TEST: (Modbus master stack initialized)'),
|
||||
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) MB_TCP_MASTER_PORT: (Connected [0-9]+ slaves), start polling'),
|
||||
Stages.STACK_START: (r'I \(([0-9]+)\) MASTER_TEST: (Start modbus test)'),
|
||||
Stages.STACK_PAR_OK: (r'I \(([0-9]+)\) MASTER_TEST: Characteristic #[0-9]+ ([a-zA-Z0-9_]+)'
|
||||
r'\s\([a-zA-Z\_\%\/]+\) value =[a-zA-Z0-9\.\s]* \((0x[a-zA-Z0-9]+)\)[,\sa-z]+ successful'),
|
||||
Stages.STACK_PAR_FAIL: (r'.*E \(([0-9]+)\) MASTER_TEST: Characteristic #[0-9]+\s\(([a-zA-Z0-9_]+)\)\s'
|
||||
r'read fail, err = [0-9]+ \([_A-Z]+\)'),
|
||||
Stages.STACK_DESTROY: (r'I \(([0-9]+)\) MASTER_TEST: (Destroy master)...')}
|
||||
|
||||
LOG_LEVEL = logging.DEBUG
|
||||
LOGGER_NAME = 'modbus_test'
|
||||
logger = logging.getLogger(LOGGER_NAME)
|
||||
|
||||
test_configs = [
|
||||
'rtu',
|
||||
'ascii'
|
||||
]
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.multi_dut_modbus_serial
|
||||
@pytest.mark.parametrize('config', test_configs, indirect=True)
|
||||
@pytest.mark.parametrize(
|
||||
'count, app_path', [
|
||||
(2, f'{os.path.join(os.path.dirname(__file__), "mb_serial_master")}|{os.path.join(os.path.dirname(__file__), "mb_serial_slave")}')
|
||||
],
|
||||
indirect=True
|
||||
)
|
||||
def test_modbus_serial_communication(config: str, dut: Tuple[ModbusTestDut, ModbusTestDut]) -> None:
|
||||
dut_slave = dut[1]
|
||||
dut_master = dut[0]
|
||||
|
||||
logger.info('DUT: %s start.', dut_master.dut_get_name())
|
||||
logger.info('DUT: %s start.', dut_slave.dut_get_name())
|
||||
|
||||
dut_slave.dut_test_start(dictionary=pattern_dict_slave)
|
||||
dut_master.dut_test_start(dictionary=pattern_dict_master)
|
||||
|
||||
dut_slave.dut_check_errors()
|
||||
dut_master.dut_check_errors()
|
@ -9,7 +9,6 @@ set(EXCLUDE_COMPONENTS examples test_app test freemodbus)
|
||||
set(MB_PARAMS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../mb_example_common")
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "${MB_PARAMS_DIR}")
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Modbus TCP Master Example
|
||||
|
||||
|
@ -2,3 +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")
|
||||
|
6
test/tcp/mb_tcp_master/main/idf_component.yml
Normal file
6
test/tcp/mb_tcp_master/main/idf_component.yml
Normal file
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
idf: ">=4.1"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
||||
rules:
|
||||
- if: "idf_version >=5.0"
|
@ -15,6 +15,11 @@
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
#if __has_include("esp_mac.h")
|
||||
#include "esp_mac.h"
|
||||
#endif
|
||||
|
||||
#include "mdns.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
@ -68,7 +73,7 @@ static const char *TAG = "MASTER_TEST";
|
||||
// Enumeration of modbus device addresses accessed by master device
|
||||
// Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
|
||||
enum {
|
||||
MB_DEVICE_ADDR1 = 1, // Slave address 1
|
||||
MB_DEVICE_ADDR1 = 1, // Slave UID = 1
|
||||
MB_DEVICE_ADDR2 = 200,
|
||||
MB_DEVICE_ADDR3 = 35
|
||||
};
|
||||
@ -180,7 +185,7 @@ static int master_get_slave_ip_stdin(char** addr_table)
|
||||
ESP_ERROR_CHECK(example_configure_stdin_stdout());
|
||||
while(1) {
|
||||
if (addr_table[ip_cnt] && strcmp(addr_table[ip_cnt], "FROM_STDIN") == 0) {
|
||||
printf("Waiting IP%d from stdin:\r\n", ip_cnt);
|
||||
printf("Waiting IP%d from stdin:\r\n", (int)ip_cnt);
|
||||
while (fgets(buf, sizeof(buf), stdin) == NULL) {
|
||||
fputs(buf, stdout);
|
||||
}
|
||||
@ -189,7 +194,7 @@ static int master_get_slave_ip_stdin(char** addr_table)
|
||||
fputc('\n', stdout);
|
||||
ip_str = master_scan_addr(&index, buf);
|
||||
if (ip_str != NULL) {
|
||||
ESP_LOGI(TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
|
||||
ESP_LOGI(TAG, "IP(%d) = [%s] set from stdin.", (int)ip_cnt, ip_str);
|
||||
if ((ip_cnt >= ip_table_sz) || (index != ip_cnt)) {
|
||||
addr_table[ip_cnt] = NULL;
|
||||
break;
|
||||
@ -202,10 +207,10 @@ static int master_get_slave_ip_stdin(char** addr_table)
|
||||
}
|
||||
} else {
|
||||
if (addr_table[ip_cnt]) {
|
||||
ESP_LOGI(TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
|
||||
ESP_LOGI(TAG, "Leave IP(%d) = [%s] set manually.", (int)ip_cnt, addr_table[ip_cnt]);
|
||||
ip_cnt++;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "IP(%d) is not set in the table.", ip_cnt);
|
||||
ESP_LOGI(TAG, "IP(%d) is not set in the table.", (int)ip_cnt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -301,7 +306,7 @@ static esp_err_t master_resolve_slave(uint8_t short_addr, mdns_result_t* result,
|
||||
char slave_name[22] = {0};
|
||||
|
||||
if (sprintf(slave_name, "mb_slave_tcp_%02X", short_addr) < 0) {
|
||||
ESP_LOGE(TAG, "Fail to create instance name for index: %d", short_addr);
|
||||
ESP_LOGE(TAG, "Fail to create instance name for index: %d", (int)short_addr);
|
||||
abort();
|
||||
}
|
||||
for (; r ; r = r->next) {
|
||||
@ -323,7 +328,7 @@ static esp_err_t master_resolve_slave(uint8_t short_addr, mdns_result_t* result,
|
||||
}
|
||||
slave_ip = master_get_slave_ip_str(r->addr, addr_type);
|
||||
if (slave_ip) {
|
||||
ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
|
||||
ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, (unsigned)r->port);
|
||||
*resolved_ip = slave_ip;
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -362,7 +367,7 @@ static int master_create_slave_list(mdns_result_t* results, char** addr_table,
|
||||
// Resolve new slave IP address using its short address
|
||||
esp_err_t err = master_resolve_slave(slave_addr, results, &slave_ip, addr_type);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Index: %d, sl_addr: %d, failed to resolve!", i, slave_addr);
|
||||
ESP_LOGE(TAG, "Index: %d, sl_addr: %d, failed to resolve!", (int)i, (int)slave_addr);
|
||||
// Set correspond index to NULL indicate host not resolved
|
||||
ip_table[ip_index] = NULL;
|
||||
continue;
|
||||
@ -379,7 +384,7 @@ static int master_create_slave_list(mdns_result_t* results, char** addr_table,
|
||||
LIST_INSERT_HEAD(&slave_addr_list, new_slave_entry, entries);
|
||||
ip_table[ip_index] = slave_ip;
|
||||
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, resolved to IP: [%s]",
|
||||
i, slave_addr, slave_ip);
|
||||
(int)i, (int)slave_addr, slave_ip);
|
||||
cid_resolve_cnt++;
|
||||
if (ip_index < addr_table_size) {
|
||||
ip_index++;
|
||||
@ -387,11 +392,11 @@ static int master_create_slave_list(mdns_result_t* results, char** addr_table,
|
||||
} else {
|
||||
ip_table[ip_index] = it ? it->ip_address : ip_table[ip_index];
|
||||
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, set to IP: [%s]",
|
||||
i, slave_addr, ip_table[ip_index]);
|
||||
(int)i, (int)slave_addr, ip_table[ip_index]);
|
||||
cid_resolve_cnt++;
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Resolved %d cids, with %d IP addresses", cid_resolve_cnt, ip_index);
|
||||
ESP_LOGI(TAG, "Resolved %d cids, with %d IP addresses", (int)cid_resolve_cnt, (int)ip_index);
|
||||
return cid_resolve_cnt;
|
||||
}
|
||||
|
||||
@ -424,7 +429,7 @@ static void master_destroy_slave_list(char** table, size_t ip_table_size)
|
||||
{
|
||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||
slave_addr_entry_t *it;
|
||||
LIST_FOREACH(it, &slave_addr_list, entries) {
|
||||
while ((it = LIST_FIRST(&slave_addr_list))) {
|
||||
LIST_REMOVE(it, entries);
|
||||
free(it);
|
||||
}
|
||||
@ -466,7 +471,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", (int)param_descriptor->cid);
|
||||
assert(instance_ptr != NULL);
|
||||
}
|
||||
return instance_ptr;
|
||||
@ -500,11 +505,11 @@ static void master_operation_func(void *arg)
|
||||
err = mbc_master_get_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%08x) read successful.",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
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);
|
||||
@ -512,14 +517,14 @@ static void master_operation_func(void *arg)
|
||||
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%08x), write successful.",
|
||||
param_descriptor->cid,
|
||||
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).",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
@ -527,7 +532,7 @@ static void master_operation_func(void *arg)
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
@ -539,8 +544,8 @@ static void master_operation_func(void *arg)
|
||||
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%x) read successful.",
|
||||
param_descriptor->cid,
|
||||
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,
|
||||
@ -554,7 +559,7 @@ static void master_operation_func(void *arg)
|
||||
uint8_t state = *(uint8_t*)temp_data_ptr;
|
||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
(const char*)rw_str,
|
||||
@ -566,7 +571,7 @@ static void master_operation_func(void *arg)
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
(int)param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
@ -580,7 +585,7 @@ static void master_operation_func(void *arg)
|
||||
|
||||
if (alarm_state) {
|
||||
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
|
||||
param_descriptor->cid);
|
||||
(int)param_descriptor->cid);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
|
||||
MASTER_MAX_RETRY);
|
||||
@ -599,17 +604,17 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"nvs_flash_init fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
result = esp_netif_init();
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_netif_init fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
result = esp_event_loop_create_default();
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_event_loop_create_default fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||
// Start mdns service and register device
|
||||
master_start_mdns_service();
|
||||
@ -621,13 +626,13 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"example_connect fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
result = esp_wifi_set_ps(WIFI_PS_NONE);
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_wifi_set_ps fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
#endif
|
||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||
int res = 0;
|
||||
@ -635,7 +640,7 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
||||
res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
|
||||
}
|
||||
if (res < num_device_parameters) {
|
||||
ESP_LOGE(TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
|
||||
ESP_LOGE(TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", (uint16_t)res, (uint16_t)num_device_parameters );
|
||||
ESP_LOGE(TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
@ -643,7 +648,7 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
||||
#elif CONFIG_MB_SLAVE_IP_FROM_STDIN
|
||||
int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table);
|
||||
if (ip_cnt) {
|
||||
ESP_LOGI(TAG, "Configured %d IP addresse(s).", ip_cnt);
|
||||
ESP_LOGI(TAG, "Configured %d IP addresse(s).", (int)ip_cnt);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Fail to get IP address from stdin. Continue.");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
@ -661,22 +666,22 @@ static esp_err_t destroy_services(void)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"example_disconnect fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
err = esp_event_loop_delete_default();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_event_loop_delete_default fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
err = esp_netif_deinit();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_netif_deinit fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
err = nvs_flash_deinit();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"nvs_flash_deinit fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -692,26 +697,26 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mb controller initialization fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
|
||||
err = mbc_master_setup((void*)comm_info);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mb controller setup fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
|
||||
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mb controller set descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
ESP_LOGI(TAG, "Modbus master stack initialized...");
|
||||
|
||||
err = mbc_master_start();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mb controller start fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
vTaskDelay(5);
|
||||
return err;
|
||||
}
|
||||
@ -722,7 +727,7 @@ static esp_err_t master_destroy(void)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_master_destroy fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
ESP_LOGI(TAG, "Modbus master stack destroy...");
|
||||
return err;
|
||||
}
|
||||
@ -745,7 +750,6 @@ void app_main(void)
|
||||
comm_info.ip_netif_ptr = (void*)get_example_netif();
|
||||
|
||||
ESP_ERROR_CHECK(master_init(&comm_info));
|
||||
vTaskDelay(50);
|
||||
|
||||
master_operation_func(NULL);
|
||||
ESP_ERROR_CHECK(master_destroy());
|
||||
|
33
test/tcp/mb_tcp_master/sdkconfig.ci.ethernet
Normal file
33
test/tcp/mb_tcp_master/sdkconfig.ci.ethernet
Normal file
@ -0,0 +1,33 @@
|
||||
#
|
||||
# Modbus configuration
|
||||
#
|
||||
CONFIG_FMB_COMM_MODE_TCP_EN=y
|
||||
CONFIG_FMB_TCP_PORT_DEFAULT=502
|
||||
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
|
||||
CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||
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_TCP_UID_ENABLED=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_ETHERNET_EMAC_TASK_STACK_SIZE=4096
|
||||
|
||||
CONFIG_ETH_ENABLED=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ETH_PHY_INTERFACE_RMII=y
|
||||
CONFIG_ETH_USE_SPI_ETHERNET=n
|
19
test/tcp/mb_tcp_master/sdkconfig.ci.wifi
Normal file
19
test/tcp/mb_tcp_master/sdkconfig.ci.wifi
Normal file
@ -0,0 +1,19 @@
|
||||
CONFIG_FMB_COMM_MODE_TCP_EN=y
|
||||
CONFIG_FMB_TCP_PORT_DEFAULT=502
|
||||
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
|
||||
CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||
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_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID="${CI_WIFI_SSID}"
|
||||
CONFIG_EXAMPLE_WIFI_PASSWORD="${CI_WIFI_PASSW}"
|
@ -10,9 +10,12 @@ CONFIG_FMB_COMM_MODE_RTU_EN=n
|
||||
CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=2000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TIMER_PORT_ENABLED=y
|
||||
CONFIG_FMB_TIMER_ISR_IN_IRAM=y
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID="${CI_WIFI_SSID}"
|
||||
CONFIG_EXAMPLE_WIFI_PASSWORD="${CI_WIFI_PASSW}"
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Modbus Slave Example
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
set(PROJECT_NAME "modbus_tcp_slave")
|
||||
|
||||
idf_component_register(SRCS "tcp_slave.c"
|
||||
INCLUDE_DIRS ".")
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -2,7 +2,8 @@ menu "Modbus Example Configuration"
|
||||
|
||||
config MB_SLAVE_ADDR
|
||||
int "Modbus slave address"
|
||||
range 1 255
|
||||
range 1 247 if !FMB_TCP_UID_ENABLED
|
||||
range 0 247 if FMB_TCP_UID_ENABLED
|
||||
default 1
|
||||
help
|
||||
This is the Modbus slave address in the network.
|
||||
|
6
test/tcp/mb_tcp_slave/main/idf_component.yml
Normal file
6
test/tcp/mb_tcp_slave/main/idf_component.yml
Normal file
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
idf: ">=4.1"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
||||
rules:
|
||||
- if: "idf_version >=5.0"
|
@ -15,9 +15,13 @@
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "mdns.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
#if __has_include("esp_mac.h")
|
||||
#include "esp_mac.h"
|
||||
#endif
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "mbcontroller.h" // for mbcontroller defines and api
|
||||
@ -48,6 +52,8 @@
|
||||
| MB_EVENT_COILS_WR)
|
||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||
|
||||
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
|
||||
|
||||
static const char *TAG = "SLAVE_TEST";
|
||||
|
||||
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
@ -65,8 +71,6 @@ static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
#define MB_DEVICE_ID (uint32_t)CONFIG_FMB_CONTROLLER_SLAVE_ID
|
||||
#endif
|
||||
|
||||
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
|
||||
|
||||
#define MB_MDNS_INSTANCE(pref) pref"mb_slave_tcp"
|
||||
|
||||
// convert mac from binary format to string
|
||||
@ -176,11 +180,11 @@ static void slave_operation_func(void *arg)
|
||||
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,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(uint32_t)reg_info.size);
|
||||
(unsigned)reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(int)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
if (reg_info.address == (uint8_t*)&holding_reg_params.holding_data0)
|
||||
{
|
||||
portENTER_CRITICAL(¶m_lock);
|
||||
@ -193,28 +197,28 @@ static void slave_operation_func(void *arg)
|
||||
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
||||
ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(uint32_t)reg_info.size);
|
||||
(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));
|
||||
ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(uint32_t)reg_info.size);
|
||||
(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));
|
||||
ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(uint32_t)reg_info.mb_offset,
|
||||
(uint32_t)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
(uint32_t)reg_info.size);
|
||||
(unsigned)reg_info.time_stamp,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(int)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
if (coil_reg_params.coils_port1 == 0xFF) break;
|
||||
}
|
||||
}
|
||||
@ -233,17 +237,17 @@ static esp_err_t init_services(void)
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"nvs_flash_init fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
result = esp_netif_init();
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_netif_init fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
result = esp_event_loop_create_default();
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_event_loop_create_default fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||
// Start mdns service and register device
|
||||
start_mdns_service();
|
||||
@ -255,13 +259,13 @@ static esp_err_t init_services(void)
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"example_connect fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
result = esp_wifi_set_ps(WIFI_PS_NONE);
|
||||
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_wifi_set_ps fail, returns(0x%x).",
|
||||
(uint32_t)result);
|
||||
(int)result);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -274,22 +278,22 @@ static esp_err_t destroy_services(void)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"example_disconnect fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
err = esp_event_loop_delete_default();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_event_loop_delete_default fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
err = esp_netif_deinit();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_netif_deinit fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
err = nvs_flash_deinit();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"nvs_flash_deinit fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||
stop_mdns_service();
|
||||
#endif
|
||||
@ -311,13 +315,14 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
|
||||
comm_info->ip_addr = NULL; // Bind to any address
|
||||
comm_info->ip_netif_ptr = (void*)get_example_netif();
|
||||
comm_info->slave_uid = MB_SLAVE_ADDR;
|
||||
|
||||
// Setup communication parameters and start stack
|
||||
err = mbc_slave_setup((void*)comm_info);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_setup fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
|
||||
// The code below initializes Modbus register area descriptors
|
||||
// for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
|
||||
@ -333,7 +338,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(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
|
||||
@ -343,7 +348,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
|
||||
// Initialization of Input Registers area
|
||||
reg_area.type = MB_PARAM_INPUT;
|
||||
@ -354,7 +359,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
reg_area.type = MB_PARAM_INPUT;
|
||||
reg_area.start_offset = MB_REG_INPUT_START_AREA1;
|
||||
reg_area.address = (void*)&input_reg_params.input_data4;
|
||||
@ -363,7 +368,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
|
||||
// Initialization of Coils register area
|
||||
reg_area.type = MB_PARAM_COIL;
|
||||
@ -374,7 +379,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
|
||||
// Initialization of Discrete Inputs register area
|
||||
reg_area.type = MB_PARAM_DISCRETE;
|
||||
@ -385,7 +390,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
|
||||
// Set values into known state
|
||||
setup_reg_data();
|
||||
@ -395,7 +400,7 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_start fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
vTaskDelay(5);
|
||||
return err;
|
||||
}
|
||||
@ -406,7 +411,7 @@ static esp_err_t slave_destroy(void)
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"mbc_slave_destroy fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
(int)err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -419,6 +424,7 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(init_services());
|
||||
|
||||
// Set UART log level
|
||||
|
||||
esp_log_level_set(TAG, ESP_LOG_INFO);
|
||||
|
||||
mb_communication_info_t comm_info = { 0 };
|
||||
|
34
test/tcp/mb_tcp_slave/sdkconfig.ci.ethernet
Normal file
34
test/tcp/mb_tcp_slave/sdkconfig.ci.ethernet
Normal file
@ -0,0 +1,34 @@
|
||||
#
|
||||
# Modbus configuration
|
||||
#
|
||||
CONFIG_FMB_COMM_MODE_TCP_EN=y
|
||||
CONFIG_FMB_TCP_PORT_DEFAULT=502
|
||||
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
|
||||
CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||
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_TIMER_PORT_ENABLED=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_ETHERNET_EMAC_TASK_STACK_SIZE=4096
|
||||
|
||||
CONFIG_ETH_ENABLED=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ETH_PHY_INTERFACE_RMII=y
|
||||
CONFIG_ETH_USE_SPI_ETHERNET=n
|
20
test/tcp/mb_tcp_slave/sdkconfig.ci.wifi
Normal file
20
test/tcp/mb_tcp_slave/sdkconfig.ci.wifi
Normal file
@ -0,0 +1,20 @@
|
||||
CONFIG_FMB_COMM_MODE_TCP_EN=y
|
||||
CONFIG_FMB_TCP_PORT_DEFAULT=502
|
||||
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
|
||||
CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||
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_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID="${CI_WIFI_SSID}"
|
||||
CONFIG_EXAMPLE_WIFI_PASSWORD="${CI_WIFI_PASSW}"
|
@ -8,13 +8,17 @@ CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||
CONFIG_FMB_COMM_MODE_RTU_EN=n
|
||||
CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=1000
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=2000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TIMER_PORT_ENABLED=y
|
||||
CONFIG_FMB_TIMER_ISR_IN_IRAM=y
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_MB_MDNS_IP_RESOLVER=n
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_MB_SLAVE_IP_FROM_STDIN=y
|
||||
CONFIG_MB_SLAVE_ADDR=1
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID="${CI_WIFI_SSID}"
|
||||
CONFIG_EXAMPLE_WIFI_PASSWORD="${CI_WIFI_PASSW}"
|
||||
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=y
|
||||
|
69
test/tcp/pytest_mb_tcp_master_slave.py
Normal file
69
test/tcp/pytest_mb_tcp_master_slave.py
Normal file
@ -0,0 +1,69 @@
|
||||
# SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# This is the script to reproduce the issue when the expect() is called from
|
||||
# main thread in Multi DUT case.
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from conftest import ModbusTestDut, Stages
|
||||
|
||||
pattern_dict_slave = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_connect: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||
Stages.STACK_IPV6: (r'I \([0-9]+\) example_connect: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
||||
Stages.STACK_INIT: (r'I \(([0-9]+)\) MB_TCP_SLAVE_PORT: (Protocol stack initialized).'),
|
||||
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) MB_TCP_SLAVE_PORT: Socket \(#[0-9]+\), accept client connection from address: '
|
||||
r'([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||
Stages.STACK_START: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Start modbus test)'),
|
||||
Stages.STACK_PAR_OK: (r'I\s\(([0-9]+)\) SLAVE_TEST: ([A-Z]+ [A-Z]+) \([a-zA-Z0-9_]+ us\),\s'
|
||||
r'ADDR:([0-9]+), TYPE:[0-9]+, INST_ADDR:0x[a-zA-Z0-9]+, SIZE:[0-9]+'),
|
||||
Stages.STACK_PAR_FAIL: (r'E \(([0-9]+)\) SLAVE_TEST: Response time exceeds configured [0-9]+ [ms], ignore packet'),
|
||||
Stages.STACK_DESTROY: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Modbus controller destroyed).')}
|
||||
|
||||
pattern_dict_master = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_connect: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||
Stages.STACK_IPV6: (r'I \([0-9]+\) example_connect: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
||||
Stages.STACK_INIT: (r'I \(([0-9]+)\) MASTER_TEST: (Modbus master stack initialized)'),
|
||||
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) MB_TCP_MASTER_PORT: (Connected [0-9]+ slaves), start polling'),
|
||||
Stages.STACK_START: (r'I \(([0-9]+)\) MASTER_TEST: (Start modbus test)'),
|
||||
Stages.STACK_PAR_OK: (r'I \(([0-9]+)\) MASTER_TEST: Characteristic #[0-9]+ ([a-zA-Z0-9_]+)'
|
||||
r'\s\([a-zA-Z\_\%\/]+\) value =[a-zA-Z0-9\.\s]* \((0x[a-zA-Z0-9]+)\)[,\sa-z]+ successful'),
|
||||
Stages.STACK_PAR_FAIL: (r'.*E \(([0-9]+)\) MASTER_TEST: Characteristic #[0-9]+\s\(([a-zA-Z0-9_]+)\)\s'
|
||||
r'read fail, err = [x0-9]+ \([_A-Z]+\)'),
|
||||
Stages.STACK_DESTROY: (r'I \(([0-9]+)\) MASTER_TEST: (Destroy master)...')}
|
||||
|
||||
LOG_LEVEL = logging.DEBUG
|
||||
LOGGER_NAME = 'modbus_test'
|
||||
logger = logging.getLogger(LOGGER_NAME)
|
||||
|
||||
test_configs = [
|
||||
'wifi',
|
||||
'ethernet'
|
||||
]
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.multi_dut_modbus_tcp
|
||||
@pytest.mark.parametrize('config', test_configs, indirect=True)
|
||||
@pytest.mark.parametrize(
|
||||
'count, app_path', [
|
||||
(2, f'{os.path.join(os.path.dirname(__file__), "mb_tcp_master")}|{os.path.join(os.path.dirname(__file__), "mb_tcp_slave")}')
|
||||
],
|
||||
indirect=True
|
||||
)
|
||||
def test_modbus_tcp_communication(dut: Tuple[ModbusTestDut, ModbusTestDut]) -> None:
|
||||
dut_slave = dut[1]
|
||||
dut_master = dut[0]
|
||||
|
||||
logger.info('DUT: %s start.', dut_master.dut_get_name())
|
||||
logger.info('DUT: %s start.', dut_slave.dut_get_name())
|
||||
|
||||
dut_slave_ip_address = dut_slave.dut_get_ip()
|
||||
dut_master.dut_send_ip(dut_slave_ip_address)
|
||||
|
||||
dut_slave.dut_test_start(dictionary=pattern_dict_slave)
|
||||
dut_master.dut_test_start(dictionary=pattern_dict_master)
|
||||
|
||||
dut_slave.dut_check_errors()
|
||||
dut_master.dut_check_errors()
|
16
tools/ignore_build_warnings.txt
Normal file
16
tools/ignore_build_warnings.txt
Normal file
@ -0,0 +1,16 @@
|
||||
library/error\.o
|
||||
/.*error\S*\.o
|
||||
.*error.*\.c\.obj
|
||||
.*error.*\.c
|
||||
.*error.*\.cpp\.obj
|
||||
.*error.*\.cxx\.obj
|
||||
.*error.*\.cc\.obj
|
||||
-Werror
|
||||
error\.d
|
||||
/.*error\S*.d
|
||||
reassigning to symbol
|
||||
changes choice state
|
||||
crosstool_version_check\.cmake
|
||||
CryptographyDeprecationWarning
|
||||
Warning: \d+/\d+ app partitions are too small for binary
|
||||
CMake Deprecation Warning at main/lib/tinyxml2/CMakeLists\.txt:11 \(cmake_policy\)
|
Reference in New Issue
Block a user