Compare commits

..

51 Commits

Author SHA1 Message Date
48c157bc46 mdns: fix build issue with CONFIG_LWIP_IPV6 disabled 2022-09-02 16:13:17 +05:30
444fae9066 Merge pull request #115 from david-cermak/bugfix/cmux_exit_bg96
fix(esp_modem): Correct exit of CMUX mode
2022-08-29 16:13:31 +02:00
2099434b3f fix(esp_modem): Correct exit of CMUX mode
* Fix DISC message's control field (0xFF->0xFE) to keep Poll bit cleared
* Accept UIH resp on DISC for both (0xFF, 0xFE) ignoring P/F bit
* Fix timeout processing when handling DISC message

Closes https://github.com/espressif/esp-protocols/issues/103
2022-08-19 11:45:59 +02:00
8f00fc182a Merge pull request #114 from david-cermak/bugfix/dns-header-bit-order
mdns: fix bit order issue in DNS header flags (updated)
2022-08-19 09:03:04 +02:00
d74c296182 fix(mdns): Example makefile to add only mdns as extra comps 2022-08-18 16:41:38 +02:00
c4e85bd099 mdns: fix bit order issue in DNS header flags
The bit field in the header flags does not match its intended order on
little endian machines. The PR removes the bit field and uses bit
operations instead.
2022-08-18 16:39:38 +02:00
85ba60e405 Merge pull request #88 from david-cermak/bugfix/modem_better_exception_report
fix(esp-modem): Add filename/line info to exception message
2022-08-18 15:27:47 +02:00
89e1bd27b3 fix(esp-modem): Add filename/line info to exception message
This is useful if exceptions are enabled, but caught internally on C++ API boundary
2022-08-18 14:52:21 +02:00
341fcb0f40 Merge pull request #112 from gabsuren/bugfix/updated_esp_modem_package
esp_modem: updated package version to 0.1.19 (IDFGH-8032)
2022-08-18 14:47:47 +02:00
469f953b28 esp_modem: updated package version to 0.1.19 2022-08-18 15:59:48 +04:00
381eb314dc Merge pull request #93 from gabsuren/feature/websocket_json_example
websocket: updated example to show how to transfer json data
2022-08-15 14:50:48 +02:00
1ffc20c8e3 Merge pull request #105 from gabsuren/websocket/version_change_03
esp_websocket_client: upgraded package version to 0.0.3 (IDFGH-7986)
2022-08-05 12:37:40 +02:00
5c245dbdb5 esp_websocket_client: Upgraded version to 0.0.3 2022-08-05 10:21:41 +04:00
134a9a9eee Revert "bugfix: mdns IPv6 address convert error"
This reverts commit 238ee96783.
2022-08-04 15:52:40 +04:00
010f98ca80 Merge pull request #99 from gabsuren/bugfix/fix_ci_build
CI: Fix build issues
2022-07-29 11:10:11 +02:00
6e4e4fab1d CI: Fix build issues 2022-07-28 22:47:53 +04:00
b6852a0588 Merge pull request #96 from gjc13/bugfix/aa-bit-receive
fix(mdns): ignore authoritative flag on reception (IDFGH-7891)
2022-07-25 08:26:10 +02:00
415e04a55f fix(mdns): ignore authoritative flag on reception 2022-07-22 22:25:08 +08:00
3456781494 websocket: updated example to show json data transfer 2022-07-21 16:04:58 +04:00
d1129f3d19 esp_err_to_name (IDFGH-7793) (#78)
fix(esp-modem): Use err_to_name to log error message on error
2022-07-18 17:08:15 +02:00
973837dd66 Merge pull request #92 from david-cermak/feat/mdns_explicit_deps
feat(mdns): Define explicit dependencies on esp-wifi
2022-07-18 17:05:44 +02:00
36de9afe0c feat(mdns): Define explicit dependencies on esp-wifi 2022-07-18 09:49:03 +02:00
0d5081b841 Merge pull request #81 from lcj446068124/bugfix/mdns_ipv6_convert_error
bugfix: mdns IPv6 address convert error (IDFGH-7772)
2022-07-15 08:13:06 +02:00
85c7282641 Merge pull request #91 from Lapshin/feature/bump-versions
Bump asio/mdns/esp_websocket_client versions
2022-07-15 07:13:35 +02:00
57afa38f49 Bump asio/mdns/esp_websocket_client versions
Update components version afrer change d66f9dc158
2022-07-14 20:04:28 +04:00
238ee96783 bugfix: mdns IPv6 address convert error
In this fix, we manually convert esp_ip_addr_t to ip_addr_t.
2022-07-14 23:40:08 +08:00
10e6348e09 Merge pull request #85 from david-cermak/feature/modem_operator_name_add_act
feat(esp_modem): Add optional ACT to operator-name
2022-07-13 16:20:54 +02:00
a286634359 feat(esp_modem): Add optional ACT to operator-name
Closes https://github.com/espressif/esp-protocols/issues/80
2022-07-13 09:56:29 +02:00
4cdfc857ad Merge pull request #68 from gabsuren/refactor/organize_yml_files
CI: Organize GitHub workflow structures
2022-07-12 20:04:01 +02:00
371a32d4ae Merge pull request #72 from david-cermak/bugfix/modem_c_api_pdp_ctx
fix(esp-modem): Add missing set_pdp_context() to C-API
2022-07-12 20:03:03 +02:00
dc4e54e99a Merge pull request #87 from Lapshin/fix/ignore-format-warnings
ignore format warnings
2022-07-12 20:02:30 +02:00
d66f9dc158 ignore format warnings 2022-07-12 18:13:01 +04:00
4980ac85b7 fix(esp-modem): Add missing set_pdp_context() to C-API 2022-07-12 15:52:39 +02:00
626eb52d04 CI: Organize github workflow structure 2022-07-12 17:24:41 +04:00
82b1aa9280 Merge pull request #73 from Lapshin/fix/ignore-format-warnings
esp_modem: Ignore format warnings (IDFGH-7760)
2022-07-12 10:44:26 +02:00
e8145fcede esp_modem: Ignore format warnings 2022-07-12 12:32:15 +04:00
9c3e24b6cf Merge pull request #70 from david-cermak/bugfix/modem_ap2ppp_retry
fix(esp_modem): Update ap2ppp example to recover network on disconnection
2022-07-11 19:11:48 +02:00
b4d85d6aae Merge pull request #84 from Lapshin/fix/asio-exampels-build
asio: fix exampels build (IDFGH-7792)
2022-07-11 19:02:36 +02:00
0b102f6286 mdns: Fix test_app build 2022-07-11 20:39:56 +04:00
06e7baf2c2 CI: Fix ASIO build in CI run 2022-07-11 19:00:06 +04:00
3662c149fb asio: Fix exampels build 2022-07-11 18:01:46 +04:00
a243d7e878 fix(esp_modem): Update ap2ppp example to recover network on disconnection
Closes https://github.com/espressif/esp-protocols/issues/44
2022-07-01 13:52:49 +02:00
ef1bae5cdd Merge pull request #35 from ESP-YJM/pr/optimize_websocket
feat(websocket): Optimize memory size for websocket client init (IDFGH-7357)
2022-06-28 16:04:09 +02:00
4cefcd3606 feat(websocket): Optimize memory size for websocket client init 2022-06-28 21:09:05 +08:00
a177b3d024 Merge pull request #67 from gabsuren/bugfix/websocket_ci_long_run
CI: Fix CI long run on websocket examples
2022-06-28 13:59:56 +02:00
b7e73d25a7 CI: Fix CI long run on websocket examples 2022-06-28 15:25:40 +04:00
9b403d477f Merge pull request #64 from bbinet/custom-source-clk
Allow to customize uart source_clk (IDFGH-7659)
2022-06-24 16:24:00 +02:00
d723fb7a5a Allow to customize uart source_clk
This is for example needed when using an external crystal to select
UART_SCLK_XTAL, which fixes uart comm issue when using PM with light
sleep enabled.
2022-06-24 14:44:15 +02:00
9905fe4cf6 Merge pull request #62 from gabsuren/asio_submodule_migration_with_history
ASIO: Initial version based on IDF 5.0 with history
2022-06-24 14:29:39 +02:00
8dc3e5835c Merge pull request #63 from bbinet/add-raw-command
Add raw command (IDFGH-7658)
2022-06-23 18:00:42 +02:00
0cf08fb676 Add "at" api for custom commands 2022-06-23 17:40:06 +02:00
71 changed files with 760 additions and 389 deletions

View File

@ -1,36 +0,0 @@
name: Build
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
idf_target: ["esp32"]
exclude:
- idf_ver: "release-v4.1"
example: modem_console
- idf_ver: "release-v4.1"
example: ap_to_pppos
- idf_ver: "release-v4.1"
example: simple_cmux_client
- idf_ver: "release-v4.2"
example: simple_cmux_client
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@master
with:
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
idf.py build

View File

@ -1,38 +0,0 @@
name: Build mDNS
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/examples/
idf.py set-target ${{ matrix.idf_target }}
cat sdkconfig.ci.eth_def >> sdkconfig.defaults
idf.py build
rm sdkconfig.defaults
cat sdkconfig.ci.eth_custom_netif >> sdkconfig.defaults
idf.py build
rm sdkconfig.defaults
cat sdkconfig.ci.eth_socket >> sdkconfig.defaults
idf.py build
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_apps/
idf.py set-target ${{ matrix.idf_target }}
idf.py build

View File

@ -1,78 +0,0 @@
name: Build Websockets
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
working-directory: components/esp_websocket_client/examples/
run: |
. ${IDF_PATH}/export.sh
cat sdkconfig.ci >> sdkconfig.defaults
idf.py build
- name: Merge binaries
working-directory: components/esp_websocket_client/examples/build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/build/
if-no-files-found: error
run-target:
name: Run Example Test on target
needs: build
strategy:
fail-fast: false
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
container:
image: python:3.7-buster
options: --privileged # Privileged mode has access to serial ports
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/build/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
pip install -r $GITHUB_WORKSPACE/components/esp_websocket_client/examples/requirements.txt
- name: Download Example Test to target
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
- name: Run Example Test on target
working-directory: components/esp_websocket_client/examples
run: |
cp sdkconfig.ci sdkconfig.defaults
pytest --log-cli-level DEBUG --junit-xml=./test_app_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
- uses: actions/upload-artifact@v2
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: examples/*.xml

View File

@ -1,28 +0,0 @@
name: Build ASIO
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2"]
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/asio/examples/${{ matrix.example }}
idf.py set-target ${{ matrix.idf_target }}
idf.py build

View File

@ -4,7 +4,7 @@ on: [push, pull_request]
jobs:
host_test:
name: Build and test
name: Build and Test on Host
runs-on: ubuntu-20.04
container: espressif/idf:release-v4.3
env:

169
.github/workflows/target-test.yml vendored Normal file
View File

@ -0,0 +1,169 @@
name: Build and Run Target tests
on: [push, pull_request]
jobs:
build_esp_modem:
strategy:
matrix:
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
idf_target: ["esp32"]
exclude:
- idf_ver: "release-v4.1"
example: modem_console
- idf_ver: "release-v4.1"
example: ap_to_pppos
- idf_ver: "release-v4.1"
example: simple_cmux_client
- idf_ver: "release-v4.2"
example: simple_cmux_client
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
idf.py build
build_mdns:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2", "esp32c3"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/examples/
idf.py set-target ${{ matrix.idf_target }}
cat sdkconfig.ci.eth_def >> sdkconfig.defaults
idf.py build
rm sdkconfig.defaults
cat sdkconfig.ci.eth_custom_netif >> sdkconfig.defaults
idf.py build
rm sdkconfig.defaults
cat sdkconfig.ci.eth_socket >> sdkconfig.defaults
idf.py build
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_apps/
idf.py set-target ${{ matrix.idf_target }}
idf.py build
build_asio:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32", "esp32s2"]
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
path: esp-protocols
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
cd $GITHUB_WORKSPACE/esp-protocols/components/asio/examples/${{ matrix.example }}
idf.py set-target ${{ matrix.idf_target }}
idf.py build
build_websocket:
strategy:
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
working-directory: components/esp_websocket_client/examples/
run: |
. ${IDF_PATH}/export.sh
cat sdkconfig.ci >> sdkconfig.defaults
idf.py build
- name: Merge binaries
working-directory: components/esp_websocket_client/examples/build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
- uses: actions/upload-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/build/
if-no-files-found: error
run-target:
name: Run Websocket Example Test on target
needs: build_websocket
strategy:
fail-fast: false
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
container:
image: python:3.7-buster
options: --privileged # Privileged mode has access to serial ports
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: components/esp_websocket_client/examples/build/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
run: |
pip install -r $GITHUB_WORKSPACE/components/esp_websocket_client/examples/requirements.txt
- name: Download Example Test to target
run: python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 components/esp_websocket_client/examples/build/flash_image.bin
- name: Run Example Test on target
working-directory: components/esp_websocket_client/examples
run: |
cp sdkconfig.ci sdkconfig.defaults
pytest --log-cli-level DEBUG --junit-xml=./test_app_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml --target=${{ matrix.idf_target }}
- uses: actions/upload-artifact@v2
if: always()
with:
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}
path: examples/*.xml

View File

@ -1,4 +1,4 @@
idf_component_register(SRCS "connect.c" "stdin_out.c" "addr_from_stdin.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES esp_netif driver esp_eth
PRIV_REQUIRES esp_netif driver esp_eth esp_wifi vfs
)

View File

@ -27,6 +27,7 @@ idf_component_register(SRCS ${asio_sources}
INCLUDE_DIRS "asio/asio/include" "port/include"
PRIV_INCLUDE_DIRS ${asio_priv_includes}
REQUIRES lwip)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
if(CONFIG_ASIO_SSL_SUPPORT)
if(CONFIG_ASIO_USE_ESP_WOLFSSL)

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_chat)

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(async_http_request)

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_sock4)

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
set(EXCLUDE_COMPONENTS openssl)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_tcp_echo_server)

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS ../../../../common_components/protocol_examples_common)
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_udp_echo_server)

View File

@ -1,4 +1,4 @@
version: "1.0.1"
version: "1.0.2"
description: ASIO
dependencies:
idf:

View File

@ -11,9 +11,10 @@ else()
src/esp_modem_uart.cpp
src/esp_modem_term_uart.cpp
src/esp_modem_netif.cpp)
set(dependencies driver)
set(dependencies driver esp_event esp_netif)
endif()
set(srcs ${platform_srcs}
"src/esp_modem_dte.cpp"
"src/esp_modem_dce.cpp"
@ -34,13 +35,17 @@ idf_component_register(SRCS "${srcs}"
PRIV_INCLUDE_DIRS private_include
REQUIRES ${dependencies})
set_target_properties(${COMPONENT_LIB} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS ON
)
if(${target} STREQUAL "linux")
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_FLAGS -Wno-format)
endif()
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -7,3 +7,4 @@ endif()
idf_component_register(SRCS "ap_to_pppos.c"
${NETWORK_DCE}
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -124,6 +124,38 @@ void wifi_init_softap(void)
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
void start_network(void)
{
EventBits_t bits = 0;
while ((bits & CONNECT_BIT) == 0) {
if (!modem_check_sync()) {
ESP_LOGE(TAG, "Modem does not respond, maybe in DATA mode? ...exiting network mode");
modem_stop_network();
if (!modem_check_sync()) {
ESP_LOGE(TAG, "Modem does not respond to AT ...restarting");
modem_reset();
ESP_LOGI(TAG, "Restarted");
}
continue;
}
if (!modem_check_signal()) {
ESP_LOGI(TAG, "Poor signal ...will check after 5s");
vTaskDelay(pdMS_TO_TICKS(5000));
continue;
}
if (!modem_start_network()) {
ESP_LOGE(TAG, "Modem could not enter network mode ...will retry after 10s");
vTaskDelay(pdMS_TO_TICKS(10000));
continue;
}
bits = xEventGroupWaitBits(event_group, (DISCONNECT_BIT | CONNECT_BIT), pdTRUE, pdFALSE, pdMS_TO_TICKS(30000));
if (bits & DISCONNECT_BIT) {
ESP_LOGE(TAG, "Modem got disconnected ...retrying");
modem_stop_network();
}
}
}
void app_main(void)
{
// Initialize NVS
@ -149,16 +181,7 @@ void app_main(void)
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, on_ip_event, NULL));
// Start the PPP network and wait for connection
modem_start_network();
EventBits_t bits;
do {
bits = xEventGroupWaitBits(event_group, (CONNECT_BIT | DISCONNECT_BIT), pdTRUE, pdFALSE, portMAX_DELAY);
if (bits & DISCONNECT_BIT) {
ESP_LOGW(TAG, "Modem got disconnected from the PPP server: retrying...");
modem_stop_network();
modem_start_network();
}
} while ((bits & CONNECT_BIT) == 0);
start_network();
// Initialize the AP and setup the NAT
esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap();
@ -172,11 +195,10 @@ void app_main(void)
// Provide a recovery if disconnection of some kind registered
while (true) {
bits = xEventGroupWaitBits(event_group, DISCONNECT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
EventBits_t bits = xEventGroupWaitBits(event_group, DISCONNECT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
if (bits & DISCONNECT_BIT) {
ESP_LOGW(TAG, "Modem got disconnected from the PPP server: restarting the network...");
modem_stop_network();
modem_start_network();
start_network();
}
}
}

View File

@ -47,12 +47,31 @@ void modem_deinit_network(void)
}
}
void modem_start_network()
bool modem_start_network()
{
esp_modem_set_mode(dce, ESP_MODEM_MODE_DATA);
return esp_modem_set_mode(dce, ESP_MODEM_MODE_DATA) == ESP_OK;
}
void modem_stop_network()
bool modem_stop_network()
{
esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
return esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
}
bool modem_check_sync()
{
return esp_modem_sync(dce) == ESP_OK;
}
void modem_reset()
{
esp_modem_reset(dce);
}
bool modem_check_signal()
{
int rssi, ber;
if (esp_modem_get_signal_quality(dce, &rssi, &ber) == ESP_OK) {
return rssi != 99 && rssi > 5;
}
return false;
}

View File

@ -79,6 +79,24 @@ public:
}
}
bool sync()
{
return dce_commands::sync(dte.get()) == command_result::OK;
}
void reset()
{
dce_commands::reset(dte.get());
}
bool check_signal()
{
int rssi, ber;
if (dce_commands::get_signal_quality(dte.get(), rssi, ber) != command_result::OK)
return false;
return rssi != 99 && rssi > 5;
}
[[maybe_unused]] bool init_sim(const std::string &pin)
{
// switch to command mode (in case we were in PPP mode)
@ -166,14 +184,14 @@ extern "C" esp_err_t modem_init_network(esp_netif_t *netif)
return ESP_OK;
}
extern "C" void modem_start_network()
extern "C" bool modem_start_network()
{
dce->set_mode(esp_modem::modem_mode::DATA_MODE);
return dce->set_mode(esp_modem::modem_mode::DATA_MODE);
}
extern "C" void modem_stop_network()
extern "C" bool modem_stop_network()
{
dce->set_mode(esp_modem::modem_mode::COMMAND_MODE);
return dce->set_mode(esp_modem::modem_mode::COMMAND_MODE);
}
extern "C" void modem_deinit_network()
@ -182,4 +200,19 @@ extern "C" void modem_deinit_network()
dce = nullptr;
}
extern "C" bool modem_check_sync()
{
return dce->get_module()->sync();
}
extern "C" void modem_reset()
{
dce->get_module()->reset();
}
extern "C" bool modem_check_signal()
{
return dce->get_module()->check_signal();
}
}

View File

@ -31,13 +31,18 @@ void modem_deinit_network();
/**
* @brief Starts the PPP network
*/
void modem_start_network();
bool modem_start_network();
/**
* @brief Stops the PPP network
*/
void modem_stop_network();
bool modem_stop_network();
bool modem_check_sync();
void modem_reset();
bool modem_check_signal();
#ifdef __cplusplus
}

View File

@ -61,7 +61,7 @@ int main()
bool pin_ok = true;
if (dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
throw_if_false(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
ESP_MODEM_THROW_IF_FALSE(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
usleep(1000000);
}
std::string str;

View File

@ -70,9 +70,9 @@ public:
.skip_phy_setup = false,
.intr_flags = ESP_INTR_FLAG_LEVEL1,
};
throw_if_esp_fail(usb_host_install(&host_config), "USB Host install failed");
ESP_MODEM_THROW_IF_ERROR(usb_host_install(&host_config), "USB Host install failed");
ESP_LOGD(TAG, "USB Host installed");
throw_if_false(pdTRUE == xTaskCreatePinnedToCore(usb_host_task, "usb_host", 4096, NULL, config->task_priority + 1, NULL, usb_config->xCoreID), "USB host task failed");
ESP_MODEM_THROW_IF_FALSE(pdTRUE == xTaskCreatePinnedToCore(usb_host_task, "usb_host", 4096, NULL, config->task_priority + 1, NULL, usb_config->xCoreID), "USB host task failed");
}
// Install CDC-ACM driver
@ -95,11 +95,11 @@ public:
};
if (usb_config->cdc_compliant) {
throw_if_esp_fail(this->CdcAcmDevice::open(usb_config->vid, usb_config->pid,
ESP_MODEM_THROW_IF_ERROR(this->CdcAcmDevice::open(usb_config->vid, usb_config->pid,
usb_config->interface_idx, &esp_modem_cdc_acm_device_config),
"USB Device open failed");
} else {
throw_if_esp_fail(this->CdcAcmDevice::open_vendor_specific(usb_config->vid, usb_config->pid,
ESP_MODEM_THROW_IF_ERROR(this->CdcAcmDevice::open_vendor_specific(usb_config->vid, usb_config->pid,
usb_config->interface_idx, &esp_modem_cdc_acm_device_config),
"USB Device open failed");
}

View File

@ -4,3 +4,4 @@ idf_component_register(SRCS "modem_console_main.cpp"
"ping_handle.c"
REQUIRES console esp_http_client nvs_flash esp_modem esp_modem_usb_dte
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -1,2 +1,3 @@
idf_component_register(SRCS "pppos_client_main.c"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -22,11 +22,13 @@ static EventGroupHandle_t event_group = NULL;
static const int CONNECT_BIT = BIT0;
static const int GOT_DATA_BIT = BIT2;
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch (event->event_id) {
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/esp-pppos", 0);
@ -59,7 +61,6 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
ESP_LOGI(TAG, "MQTT other event id: %d", event->event_id);
break;
}
return ESP_OK;
}
static void on_ppp_changed(void *arg, esp_event_base_t event_base,
@ -200,11 +201,17 @@ void app_main(void)
/* Wait for IP address */
xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
/* Config MQTT */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_client_config_t mqtt_config = {
.broker.address.uri = BROKER_URL,
};
#else
esp_mqtt_client_config_t mqtt_config = {
.uri = BROKER_URL,
.event_handle = mqtt_event_handler,
};
#endif
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
esp_mqtt_client_destroy(mqtt_client);

View File

@ -82,7 +82,7 @@ extern "C" void app_main(void)
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
bool pin_ok = true;
if (dce->read_pin(pin_ok) == command_result::OK && !pin_ok) {
throw_if_false(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
ESP_MODEM_THROW_IF_FALSE(dce->set_pin(CONFIG_EXAMPLE_SIM_PIN) == command_result::OK, "Cannot set PIN!");
vTaskDelay(pdMS_TO_TICKS(1000)); // Need to wait for some time after unlocking the SIM
}
#endif

View File

@ -26,7 +26,11 @@ struct MqttClientHandle {
explicit MqttClientHandle(const std::string &uri)
{
esp_mqtt_client_config_t config = { };
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
config.broker.address.uri = uri.c_str();
#else
config.uri = uri.c_str();
#endif
client = esp_mqtt_client_init(&config);
esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, this);
}

View File

@ -1,4 +1,4 @@
version: "0.1.17"
version: "0.1.19"
description: esp modem
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
dependencies:

View File

@ -69,12 +69,12 @@ class Creator {
public:
Creator(std::shared_ptr<DTE> dte, esp_netif_t *esp_netif): dte(std::move(dte)), device(nullptr), netif(esp_netif)
{
throw_if_false(netif != nullptr, "Null netif");
ESP_MODEM_THROW_IF_FALSE(netif != nullptr, "Null netif");
}
Creator(std::shared_ptr<DTE> dte, esp_netif_t *esp_netif, std::shared_ptr<T_Module> dev): dte(std::move(dte)), device(std::move(dev)), netif(esp_netif)
{
throw_if_false(netif != nullptr, "Null netif");
ESP_MODEM_THROW_IF_FALSE(netif != nullptr, "Null netif");
}
~Creator()

View File

@ -104,6 +104,15 @@ public:
pdp = std::move(new_pdp);
}
/**
* @brief Simplified version of operator name (without the ACT, which is included in the command library)
*/
command_result get_operator_name(std::string& name)
{
int dummy_act;
return get_operator_name(name, dummy_act);
}
/**
* @brief Common DCE commands generated from the API AT list
*/

View File

@ -16,14 +16,21 @@
#include <string>
#include "esp_err.h"
#include "esp_log.h"
#ifndef __FILENAME__
#define __FILENAME__ __FILE__
#endif
#define ESP_MODEM_THROW_IF_FALSE(...) esp_modem::throw_if_false(__FILENAME__, __LINE__, __VA_ARGS__)
#define ESP_MODEM_THROW_IF_ERROR(...) esp_modem::throw_if_error(__FILENAME__, __LINE__, __VA_ARGS__)
namespace esp_modem {
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
#define THROW(exception) throw(exception)
#define ESP_MODEM_THROW(exception) throw(exception)
class esp_err_exception: virtual public std::exception {
public:
explicit esp_err_exception(esp_err_t err): esp_err(err) {}
explicit esp_err_exception(std::string msg): esp_err(ESP_FAIL), message(std::move(msg)) {}
explicit esp_err_exception(std::string msg, esp_err_t err): esp_err(err), message(std::move(msg)) {}
virtual esp_err_t get_err_t()
@ -31,7 +38,7 @@ public:
return esp_err;
}
~esp_err_exception() noexcept override = default;
virtual const char *what() const noexcept
[[nodiscard]] const char *what() const noexcept override
{
return message.c_str();
}
@ -39,28 +46,43 @@ private:
esp_err_t esp_err;
std::string message;
};
#else
#define THROW(exception) abort()
#define ESP_MODEM_THROW(exception) do { exception; abort(); } while(0)
class esp_err_exception {
void print(std::string msg) { ESP_LOGE("ESP_MODEM_THROW", "%s\n", msg.c_str()); }
public:
explicit esp_err_exception(std::string msg) { print(std::move(msg)); }
explicit esp_err_exception(std::string msg, esp_err_t err) { print(std::move(msg)); }
};
#endif
static inline void throw_if_false(bool condition, std::string message)
static inline std::string make_message(const std::string& filename, int line, const std::string& message = "ERROR")
{
std::string text = filename + ":" + std::to_string(line) + " " + message;
return text;
}
static inline void throw_if_false(const std::string& filename, int line, bool condition, const std::string& message)
{
if (!condition) {
THROW(esp_err_exception(std::move(message)));
ESP_MODEM_THROW(esp_err_exception(make_message(filename, line, message)));
}
}
static inline void throw_if_esp_fail(esp_err_t err, std::string message)
static inline void throw_if_error(const std::string& filename, int line, esp_err_t err, const std::string& message)
{
if (err != ESP_OK) {
THROW(esp_err_exception(std::move(message), err));
ESP_MODEM_THROW(esp_err_exception(make_message(filename, line, message), err));
}
}
static inline void throw_if_esp_fail(esp_err_t err)
static inline void throw_if_error(const std::string& filename, int line, esp_err_t err)
{
if (err != ESP_OK) {
THROW(esp_err_exception(err));
ESP_MODEM_THROW(esp_err_exception(make_message(filename, line), err));
}
}

View File

@ -15,6 +15,7 @@
#pragma once
#include "esp_modem_config.h"
#include "esp_netif.h"
#ifdef __cplusplus
extern "C" {
@ -22,7 +23,11 @@ extern "C" {
typedef struct esp_modem_dce_wrap esp_modem_dce_t;
struct PdpContext;
typedef struct esp_modem_PdpContext_t {
size_t context_id;
const char *protocol_type;
const char *apn;
} esp_modem_PdpContext_t;
/**
* @defgroup ESP_MODEM_C_API ESP_MODEM C API

View File

@ -50,7 +50,8 @@ struct esp_modem_uart_term_config {
uart_stop_bits_t stop_bits; /*!< Stop bits of UART */
uart_parity_t parity; /*!< Parity type */
esp_modem_flow_ctrl_t flow_control; /*!< Flow control type */
int baud_rate; /*!< Communication baud rate */
uart_sclk_t source_clk; /*!< UART source clock selection */
int baud_rate; /*!< Communication baud rate */
int tx_io_num; /*!< TXD Pin Number */
int rx_io_num; /*!< RXD Pin Number */
int rts_io_num; /*!< RTS Pin Number */
@ -107,6 +108,7 @@ struct esp_modem_dte_config {
.stop_bits = UART_STOP_BITS_1, \
.parity = UART_PARITY_DISABLE, \
.flow_control = ESP_MODEM_FLOW_CONTROL_NONE,\
.source_clk = UART_SCLK_APB, \
.baud_rate = 115200, \
.tx_io_num = 25, \
.rx_io_num = 26, \

View File

@ -38,7 +38,7 @@
#define BOOL_OUT(param, name) bool* _ARG(param, name)
#define INT_OUT(param, name) int* _ARG(param, name)
#define INTEGER_LIST_IN(param, name) const int* _ARG(param, name)
#define STRUCT_OUT(struct_name, p1) struct struct_name* p1
#define STRUCT_OUT(struct_name, p1) esp_modem_ ## struct_name ## _t* p1
#endif
#define DECLARE_ALL_COMMAND_APIS(...) \
@ -50,9 +50,10 @@ ESP_MODEM_DECLARE_DCE_COMMAND(sync, command_result, 0) \
/**
* @brief Reads the operator name
* @param[out] operator name
* @param[out] access technology
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 1, STRING_OUT(p1, name)) \
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 2, STRING_OUT(p1, name), INT_OUT(p2, act)) \
\
/**
* @brief Stores current user profile
@ -65,7 +66,15 @@ ESP_MODEM_DECLARE_DCE_COMMAND(store_profile, command_result, 0) \
* @param[in] pin Pin
* @return OK, FAIL or TIMEOUT
*/\
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
\
/**
* @brief Execute the supplied AT command
* @param[in] at AT command
* @param[out] out Command output string
* @return OK, FAIL or TIMEOUT
*/\
ESP_MODEM_DECLARE_DCE_COMMAND(at, command_result, 2, STRING_IN(p1, cmd), STRING_OUT(p2, out)) \
\
/**
* @brief Checks if the SIM needs a PIN
@ -89,7 +98,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_echo, command_result, 1, BOOL_IN(p1, echo_on))
ESP_MODEM_DECLARE_DCE_COMMAND(sms_txt_mode, command_result, 1, BOOL_IN(p1, txt)) \
\
/**
* @brief Sets the default (GSM) charater set
* @brief Sets the default (GSM) character set
* @return OK, FAIL or TIMEOUT
*/ \
ESP_MODEM_DECLARE_DCE_COMMAND(sms_character_set, command_result, 0) \

View File

@ -22,6 +22,7 @@
.stop_bits = UART_STOP_BITS_1, \
.parity = UART_PARITY_DISABLE, \
.flow_control = ESP_MODEM_FLOW_CONTROL_NONE,\
.source_clk = UART_SCLK_APB, \
.baud_rate = 115200, \
.tx_io_num = 25, \
.rx_io_num = 26, \

View File

@ -1,2 +1,3 @@
idf_component_register(INCLUDE_DIRS include
idf_component_register(SRCS "esp_err_to_name.c"
INCLUDE_DIRS include
REQUIRES esp_netif_linux esp_event_mock)

View File

@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: Franz Hoepfinger
*
* SPDX-License-Identifier: Apache-2.0
*/
static const char esp_unknown_msg[] = "ERROR";
const char *esp_err_to_name(int code)
{
return esp_unknown_msg;
}

View File

@ -17,4 +17,5 @@
typedef int uart_port_t;
typedef int uart_word_length_t;
typedef int uart_stop_bits_t;
typedef int uart_parity_t;
typedef int uart_parity_t;
typedef int uart_sclk_t;

View File

@ -25,3 +25,11 @@ typedef int esp_err_t;
#define ESP_ERR_NOT_FOUND 0x105
#define ESP_ERR_NOT_SUPPORTED 0x106
#define ESP_ERR_TIMEOUT 0x107
#ifdef __cplusplus
extern "C" {
#endif
const char *esp_err_to_name(int code);
#ifdef __cplusplus
}
#endif

View File

@ -22,7 +22,7 @@
action; \
} catch (::esp_modem::esp_err_exception& e) { \
esp_err_t err = e.get_err_t(); \
ESP_LOGE(TAG, "%s: Exception caught with ESP err_code=%d", __func__, err); \
ESP_LOGE(TAG, "%s: Exception caught with ESP err_code=%d %s", __func__, err, esp_err_to_name(err)); \
ESP_LOGE(TAG, "%s", e.what()); \
action; \
}

View File

@ -122,20 +122,15 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce
return ESP_ERR_INVALID_ARG;
}
if (mode == ESP_MODEM_MODE_DATA) {
dce_wrap->dce->set_data();
} else if (mode == ESP_MODEM_MODE_COMMAND) {
dce_wrap->dce->exit_data();
} else if (mode == ESP_MODEM_MODE_CMUX) {
if (dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) &&
// automatically switch to data mode for the primary terminal
dce_wrap->dce->set_mode(modem_mode::DATA_MODE)) {
return ESP_OK;
}
return ESP_FAIL;
} else {
return ESP_ERR_NOT_SUPPORTED;
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
}
return ESP_OK;
if (mode == ESP_MODEM_MODE_COMMAND) {
return dce_wrap->dce->set_mode(modem_mode::COMMAND_MODE) ? ESP_OK : ESP_FAIL;
}
if (mode == ESP_MODEM_MODE_CMUX) {
return dce_wrap->dce->set_mode(modem_mode::CMUX_MODE) ? ESP_OK : ESP_FAIL;
}
return ESP_ERR_NOT_SUPPORTED;
}
extern "C" esp_err_t esp_modem_read_pin(esp_modem_dce_t *dce_wrap, bool *pin)
@ -184,6 +179,20 @@ extern "C" esp_err_t esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pi
return command_response_to_esp_err(dce_wrap->dce->set_pin(pin_str));
}
extern "C" esp_err_t esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string out;
std::string at_str(at);
auto ret = command_response_to_esp_err(dce_wrap->dce->at(at_str, out));
if ((p_out != NULL) && (!out.empty())) {
strlcpy(p_out, out.c_str(), ESP_MODEM_C_API_STR_MAX);
}
return ret;
}
extern "C" esp_err_t esp_modem_get_signal_quality(esp_modem_dce_t *dce_wrap, int *rssi, int *ber)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
@ -379,3 +388,19 @@ extern "C" esp_err_t esp_modem_set_gnss_power_mode(esp_modem_dce_t *dce_wrap, in
}
return command_response_to_esp_err(dce_wrap->dce->set_gnss_power_mode(mode));
}
extern "C" esp_err_t esp_modem_reset(esp_modem_dce_t *dce_wrap)
{
return command_response_to_esp_err(dce_wrap->dce->reset());
}
extern "C" esp_err_t esp_modem_set_pdp_context(esp_modem_dce_t *dce_wrap, esp_modem_PdpContext_t *c_api_pdp)
{
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
esp_modem::PdpContext pdp{c_api_pdp->apn};
pdp.context_id = c_api_pdp->context_id;
pdp.protocol_type = c_api_pdp->protocol_type;
return command_response_to_esp_err(dce_wrap->dce->set_pdp_context(pdp));
}

View File

@ -82,7 +82,7 @@ void CMux::send_disconnect(size_t i)
{
if (i == 0) { // control terminal
uint8_t frame[] = {
SOF_MARKER, 0x3, 0xFF, 0x5, 0xC3, 0x1, 0xE7, SOF_MARKER };
SOF_MARKER, 0x3, 0xEF, 0x5, 0xC3, 0x1, 0xF2, SOF_MARKER };
term->write(frame, 8);
} else { // separate virtual terminal
uint8_t frame[] = {
@ -142,7 +142,7 @@ void CMux::data_available(uint8_t *data, size_t len)
read_cb[virtual_term](payload_start, total_payload_size);
#endif
}
} else if (type == 0xFF && dlci == 0) { // notify the internal DISC command
} else if ((type&FT_UIH) == FT_UIH && dlci == 0) { // notify the internal DISC command
Scoped<Lock> l(lock);
sabm_ack = dlci;
}
@ -325,11 +325,12 @@ bool CMux::on_cmux_data(uint8_t *data, size_t actual_len)
bool CMux::deinit()
{
int timeout = 0;
int timeout;
sabm_ack = -1;
// First disconnect all (2) virtual terminals
for (size_t i = 1; i < 3; i++) {
send_disconnect(i);
timeout = 0;
while (true) {
usleep(10'000);
Scoped<Lock> l(lock);
@ -345,6 +346,7 @@ bool CMux::deinit()
sabm_ack = -1;
// Then disconnect the control terminal
send_disconnect(0);
timeout = 0;
while (true) {
usleep(10'000);
Scoped<Lock> l(lock);

View File

@ -228,7 +228,7 @@ command_result set_flow_control(CommandableIf *t, int dce_flow, int dte_flow)
return generic_command_common(t, "AT+IFC=" + std::to_string(dce_flow) + ", " + std::to_string(dte_flow) + "\r");
}
command_result get_operator_name(CommandableIf *t, std::string &operator_name)
command_result get_operator_name(CommandableIf *t, std::string &operator_name, int &act)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string_view out;
@ -239,9 +239,19 @@ command_result get_operator_name(CommandableIf *t, std::string &operator_name)
auto pos = out.find("+COPS");
auto property = 0;
while (pos != std::string::npos) {
// Looking for: +COPS: <mode>[, <format>[, <oper>]]
// Looking for: +COPS: <mode>[, <format>[, <oper>[, <act>]]]
if (property++ == 2) { // operator name is after second comma (as a 3rd property of COPS string)
operator_name = out.substr(++pos);
auto additional_comma = operator_name.find(','); // check for the optional ACT
if (additional_comma != std::string::npos && std::from_chars(operator_name.data() + additional_comma + 1,operator_name.data() + operator_name.length(), act).ec != std::errc::invalid_argument) {
operator_name = operator_name.substr(0, additional_comma);
}
// and strip quotes if present
auto quote1 = operator_name.find('"');
auto quote2 = operator_name.rfind('"');
if (quote1 != std::string::npos && quote2 != std::string::npos) {
operator_name = operator_name.substr(quote1+1, quote2-1);
}
return command_result::OK;
}
pos = out.find(',', ++pos);
@ -379,6 +389,13 @@ command_result set_pin(CommandableIf *t, const std::string &pin)
return generic_command_common(t, set_pin_command);
}
command_result at(CommandableIf *t, const std::string &cmd, std::string &out)
{
ESP_LOGV(TAG, "%s", __func__ );
std::string at_command = cmd + "\r";
return generic_get_string(t, at_command, out);
}
command_result get_signal_quality(CommandableIf *t, int &rssi, int &ber)
{
ESP_LOGV(TAG, "%s", __func__ );
@ -543,4 +560,4 @@ command_result set_gnss_power_mode_sim76xx(CommandableIf *t, int mode)
return generic_command_common(t, "AT+CGPS=" + std::to_string(mode) + "\r");
}
} // esp_modem::dce_commands
} // esp_modem::dce_commands

View File

@ -56,7 +56,7 @@ command_result DTE::command(const std::string &command, got_line_cb got_line, ui
command_term->write((uint8_t *)command.c_str(), command.length());
auto got_lf = signal.wait(GOT_LINE, time_ms);
if (got_lf && res == command_result::TIMEOUT) {
throw_if_esp_fail(ESP_ERR_INVALID_STATE);
ESP_MODEM_THROW_IF_ERROR(ESP_ERR_INVALID_STATE);
}
buffer.consumed = 0;
command_term->set_read_cb(nullptr);

View File

@ -82,11 +82,11 @@ Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
driver.base.netif = ppp_netif;
driver.ppp = this;
driver.base.post_attach = esp_modem_post_attach;
throw_if_esp_fail(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void *) this));
throw_if_esp_fail(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, esp_netif_action_connected, ppp_netif));
throw_if_esp_fail(
ESP_MODEM_THROW_IF_ERROR(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, (void *) this));
ESP_MODEM_THROW_IF_ERROR(esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_GOT_IP, esp_netif_action_connected, ppp_netif));
ESP_MODEM_THROW_IF_ERROR(
esp_event_handler_register(IP_EVENT, IP_EVENT_PPP_LOST_IP, esp_netif_action_disconnected, ppp_netif));
throw_if_esp_fail(esp_netif_attach(ppp_netif, &driver));
ESP_MODEM_THROW_IF_ERROR(esp_netif_attach(ppp_netif, &driver));
}
void Netif::start()

View File

@ -28,7 +28,7 @@ void Lock::unlock()
Lock::Lock(): m(nullptr)
{
m = xSemaphoreCreateRecursiveMutex();
throw_if_false(m != nullptr, "create signal event group failed");
ESP_MODEM_THROW_IF_FALSE(m != nullptr, "create signal event group failed");
}
Lock::~Lock()
@ -45,7 +45,7 @@ void Lock::lock()
SignalGroup::SignalGroup(): event_group(nullptr)
{
event_group = xEventGroupCreate();
throw_if_false(event_group != nullptr, "create signal event group failed");
ESP_MODEM_THROW_IF_FALSE(event_group != nullptr, "create signal event group failed");
}
void SignalGroup::set(uint32_t bits)
@ -86,7 +86,7 @@ Task::Task(size_t stack_size, size_t priority, void *task_param, TaskFunction_t
: task_handle(nullptr)
{
BaseType_t ret = xTaskCreate(task_function, "vfs_task", stack_size, task_param, priority, &task_handle);
throw_if_false(ret == pdTRUE, "create vfs task failed");
ESP_MODEM_THROW_IF_FALSE(ret == pdTRUE, "create vfs task failed");
}
Task::~Task()

View File

@ -38,9 +38,9 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
uart_config.stop_bits = config->stop_bits;
uart_config.flow_ctrl = (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
: UART_HW_FLOWCTRL_DISABLE;
uart_config.source_clk = UART_SCLK_APB;
uart_config.source_clk = config->source_clk;
throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
ESP_MODEM_THROW_IF_ERROR(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
@ -49,24 +49,24 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}
throw_if_esp_fail(res, "config uart gpio failed");
ESP_MODEM_THROW_IF_ERROR(res, "config uart gpio failed");
/* Set flow control threshold */
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
res = uart_set_hw_flow_ctrl(config->port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
} else if (config->flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
res = uart_set_sw_flow_ctrl(config->port_num, true, 8, UART_FIFO_LEN - 8);
}
throw_if_esp_fail(res, "config uart flow control failed");
ESP_MODEM_THROW_IF_ERROR(res, "config uart flow control failed");
/* Install UART driver and get event queue used inside driver */
res = uart_driver_install(config->port_num,
config->rx_buffer_size, config->tx_buffer_size,
config->event_queue_size, config->event_queue_size ? event_queue : nullptr,
0);
throw_if_esp_fail(res, "install uart driver failed");
throw_if_esp_fail(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed");
ESP_MODEM_THROW_IF_ERROR(res, "install uart driver failed");
ESP_MODEM_THROW_IF_ERROR(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed");
throw_if_esp_fail(uart_set_rx_full_threshold(config->port_num, 64), "config rx full threshold failed");
ESP_MODEM_THROW_IF_ERROR(uart_set_rx_full_threshold(config->port_num, 64), "config rx full threshold failed");
/* mark UART as initialized */
port = config->port_num;

View File

@ -33,7 +33,7 @@ struct uart_task {
task_handle(nullptr)
{
BaseType_t ret = xTaskCreate(task_function, "uart_task", stack_size, task_param, priority, &task_handle);
throw_if_false(ret == pdTRUE, "create uart event task failed");
ESP_MODEM_THROW_IF_FALSE(ret == pdTRUE, "create uart event task failed");
}
~uart_task()

View File

@ -27,7 +27,7 @@ uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHand
{
ESP_LOGD(TAG, "Creating uart resource" );
struct termios tty = {};
throw_if_false(tcgetattr(fd, &tty) == 0, "Failed to tcgetattr()");
ESP_MODEM_THROW_IF_FALSE(tcgetattr(fd, &tty) == 0, "Failed to tcgetattr()");
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;

View File

@ -91,7 +91,7 @@ bool vfs_create_socket(struct esp_modem_vfs_socket_creator *config, struct esp_m
}
TRY_CATCH_OR_DO(
int fd = -1;
esp_modem::throw_if_esp_fail(hostname_to_fd(config->host_name, config->port, &fd));
ESP_MODEM_THROW_IF_ERROR(hostname_to_fd(config->host_name, config->port, &fd));
// Set the FD to non-blocking mode
int flags = fcntl(fd, F_GETFL, nullptr) | O_NONBLOCK;

View File

@ -48,7 +48,7 @@ bool vfs_create_uart(struct esp_modem_vfs_uart_creator *config, struct esp_modem
}
TRY_CATCH_OR_DO(
int fd = open(config->dev_name, O_RDWR);
esp_modem::throw_if_false(fd >= 0, "Cannot open the fd");
ESP_MODEM_THROW_IF_FALSE(fd >= 0, "Cannot open the fd");
created_config->resource = new esp_modem_vfs_resource(&config->uart, fd);
created_config->fd = fd;

View File

@ -34,6 +34,8 @@ int LoopbackTerm::write(uint8_t *data, size_t len)
response = "+CSQ: 123,456\n\r\nOK\r\n";
} else if (command.find("AT+CGMM\r") != std::string::npos) {
response = "0G Dummy Model\n\r\nOK\r\n";
} else if (command.find("AT+COPS?\r") != std::string::npos) {
response = "+COPS: 0,0,\"OperatorName\",5\n\r\nOK\r\n";
} else if (command.find("AT+CBC\r") != std::string::npos) {
response = is_bg96 ? "+CBC: 1,20,123456\r\r\n\r\nOK\r\n\n\r\n" :
"+CBC: 123.456V\r\r\n\r\nOK\r\n\n\r\n";

View File

@ -56,6 +56,14 @@ TEST_CASE("DCE AT parser", "[esp_modem]")
std::string model;
CHECK(dce->get_module_name(model) == command_result::OK);
CHECK(model == "0G Dummy Model");
std::string operator_name;
int act = 99;
CHECK(dce->get_operator_name(operator_name) == command_result::OK);
CHECK(operator_name == "OperatorName");
CHECK(dce->get_operator_name(operator_name, act) == command_result::OK);
CHECK(operator_name == "OperatorName");
CHECK(act == 5);
}

View File

@ -87,7 +87,7 @@ esp_err_t modem_init_network(esp_netif_t *netif)
return NetModule::init(netif);
}
void modem_start_network()
esp_err_t modem_start_network()
{
NetModule::start();
}

View File

@ -9,4 +9,5 @@ endif()
idf_component_register(SRCS "esp_websocket_client.c"
INCLUDE_DIRS "include"
REQUIRES lwip esp-tls tcp_transport http_parser
PRIV_REQUIRES esp_timer)
PRIV_REQUIRES esp_timer esp_event)
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -0,0 +1,10 @@
menu "ESP WebSocket client"
config ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
bool "Enable websocket client dynamic buffer for send and receive data"
default n
help
Enable this option will reallocated buffer when send or receive data and free them when end of use.
This can save about 2 KB memory when no websocket data send and receive.
endmenu

View File

@ -54,6 +54,9 @@ static const char *TAG = "WEBSOCKET_CLIENT";
action; \
}
#define WS_OVER_TCP_SCHEME "ws"
#define WS_OVER_TLS_SCHEME "wss"
const static int STOPPED_BIT = BIT0;
const static int CLOSE_FRAME_SENT_BIT = BIT1; // Indicates that a close frame was sent by the client
// and we are waiting for the server to continue with clean close
@ -78,6 +81,15 @@ typedef struct {
char *headers;
int pingpong_timeout_sec;
size_t ping_interval_sec;
const char *cert;
size_t cert_len;
const char *client_cert;
size_t client_cert_len;
const char *client_key;
size_t client_key_len;
bool use_global_ca_store;
bool skip_cert_common_name_check;
esp_err_t (*crt_bundle_attach)(void *conf);
} websocket_config_storage_t;
typedef enum {
@ -122,6 +134,45 @@ static uint64_t _tick_get_ms(void)
return esp_timer_get_time()/1000;
}
static esp_err_t esp_websocket_new_buf(esp_websocket_client_handle_t client, bool is_tx)
{
#ifdef CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
if (is_tx) {
if (client->tx_buffer) {
free(client->tx_buffer);
}
client->tx_buffer = calloc(1, client->buffer_size);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, return ESP_ERR_NO_MEM);
} else {
if (client->rx_buffer) {
free(client->rx_buffer);
}
client->rx_buffer = calloc(1, client->buffer_size);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, return ESP_ERR_NO_MEM);
}
#endif
return ESP_OK;
}
static void esp_websocket_free_buf(esp_websocket_client_handle_t client, bool is_tx)
{
#ifdef CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
if (is_tx) {
if (client->tx_buffer) {
free(client->tx_buffer);
client->tx_buffer = NULL;
}
} else {
if (client->rx_buffer) {
free(client->rx_buffer);
client->rx_buffer = NULL;
}
}
#endif
}
static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle_t client,
esp_websocket_event_id_t event,
const char *data,
@ -308,6 +359,93 @@ static esp_err_t set_websocket_transport_optional_settings(esp_websocket_client_
return ESP_ERR_INVALID_ARG;
}
static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_handle_t client)
{
if (!client->config->scheme) {
ESP_LOGE(TAG, "No scheme found");
return ESP_FAIL;
}
if (client->transport_list) {
esp_transport_list_destroy(client->transport_list);
client->transport_list = NULL;
}
client->transport_list = esp_transport_list_init();
ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, return ESP_ERR_NO_MEM);
if (strcasecmp(client->config->scheme, WS_OVER_TCP_SCHEME) == 0) {
esp_transport_handle_t tcp = esp_transport_tcp_init();
ESP_WS_CLIENT_MEM_CHECK(TAG, tcp, return ESP_ERR_NO_MEM);
esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup
if (client->keep_alive_cfg.keep_alive_enable) {
esp_transport_tcp_set_keep_alive(tcp, &client->keep_alive_cfg);
}
if (client->if_name) {
esp_transport_tcp_set_interface_name(tcp, client->if_name);
}
esp_transport_handle_t ws = esp_transport_ws_init(tcp);
ESP_WS_CLIENT_MEM_CHECK(TAG, ws, return ESP_ERR_NO_MEM);
esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, ws, WS_OVER_TCP_SCHEME);
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, WS_OVER_TCP_SCHEME), return ESP_FAIL;)
} else if (strcasecmp(client->config->scheme, WS_OVER_TLS_SCHEME) == 0) {
esp_transport_handle_t ssl = esp_transport_ssl_init();
ESP_WS_CLIENT_MEM_CHECK(TAG, ssl, return ESP_ERR_NO_MEM);
esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
if (client->config->use_global_ca_store == true) {
esp_transport_ssl_enable_global_ca_store(ssl);
} else if (client->config->cert) {
if (!client->config->cert_len) {
esp_transport_ssl_set_cert_data(ssl, client->config->cert, strlen(client->config->cert));
} else {
esp_transport_ssl_set_cert_data_der(ssl, client->config->cert, client->config->cert_len);
}
}
if (client->config->client_cert) {
if (!client->config->client_cert_len) {
esp_transport_ssl_set_client_cert_data(ssl, client->config->client_cert, strlen(client->config->client_cert));
} else {
esp_transport_ssl_set_client_cert_data_der(ssl, client->config->client_cert, client->config->client_cert_len);
}
}
if (client->config->client_key) {
if (!client->config->client_key_len) {
esp_transport_ssl_set_client_key_data(ssl, client->config->client_key, strlen(client->config->client_key));
} else {
esp_transport_ssl_set_client_key_data_der(ssl, client->config->client_key, client->config->client_key_len);
}
}
if (client->config->crt_bundle_attach) {
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
esp_transport_ssl_crt_bundle_attach(ssl, client->config->crt_bundle_attach);
#else //CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
ESP_LOGE(TAG, "crt_bundle_attach configured but not enabled in menuconfig: Please enable MBEDTLS_CERTIFICATE_BUNDLE option");
#endif
}
if (client->config->skip_cert_common_name_check) {
esp_transport_ssl_skip_common_name_check(ssl);
}
esp_transport_handle_t wss = esp_transport_ws_init(ssl);
ESP_WS_CLIENT_MEM_CHECK(TAG, wss, return ESP_ERR_NO_MEM);
esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, wss, WS_OVER_TLS_SCHEME);
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, WS_OVER_TLS_SCHEME), return ESP_FAIL;)
} else {
ESP_LOGE(TAG, "Not support this websocket scheme %s, only support %s and %s", client->config->scheme, WS_OVER_TCP_SCHEME, WS_OVER_TLS_SCHEME);
return ESP_FAIL;
}
return ESP_OK;
}
esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config)
{
esp_websocket_client_handle_t client = calloc(1, sizeof(struct esp_websocket_client));
@ -343,83 +481,31 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
client->config = calloc(1, sizeof(websocket_config_storage_t));
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail);
client->transport_list = esp_transport_list_init();
ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail);
esp_transport_handle_t tcp = esp_transport_tcp_init();
ESP_WS_CLIENT_MEM_CHECK(TAG, tcp, goto _websocket_init_fail);
esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup
esp_transport_tcp_set_keep_alive(tcp, &client->keep_alive_cfg);
esp_transport_tcp_set_interface_name(tcp, client->if_name);
esp_transport_handle_t ws = esp_transport_ws_init(tcp);
ESP_WS_CLIENT_MEM_CHECK(TAG, ws, goto _websocket_init_fail);
esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, ws, "ws");
if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) {
asprintf(&client->config->scheme, "ws");
asprintf(&client->config->scheme, WS_OVER_TCP_SCHEME);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
} else if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) {
asprintf(&client->config->scheme, WS_OVER_TLS_SCHEME);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
}
esp_transport_handle_t ssl = esp_transport_ssl_init();
ESP_WS_CLIENT_MEM_CHECK(TAG, ssl, goto _websocket_init_fail);
esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup
if (config->use_global_ca_store == true) {
esp_transport_ssl_enable_global_ca_store(ssl);
} else if (config->cert_pem) {
if (!config->cert_len) {
esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
} else {
esp_transport_ssl_set_cert_data_der(ssl, config->cert_pem, config->cert_len);
}
}
if (config->client_cert) {
if (!config->client_cert_len) {
esp_transport_ssl_set_client_cert_data(ssl, config->client_cert, strlen(config->client_cert));
} else {
esp_transport_ssl_set_client_cert_data_der(ssl, config->client_cert, config->client_cert_len);
}
}
if (config->client_key) {
if (!config->client_key_len) {
esp_transport_ssl_set_client_key_data(ssl, config->client_key, strlen(config->client_key));
} else {
esp_transport_ssl_set_client_key_data_der(ssl, config->client_key, config->client_key_len);
}
}
if (config->crt_bundle_attach) {
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
esp_transport_ssl_crt_bundle_attach(ssl, config->crt_bundle_attach);
#else //CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
ESP_LOGE(TAG, "crt_bundle_attach configured but not enabled in menuconfig: Please enable MBEDTLS_CERTIFICATE_BUNDLE option");
#endif
}
if (config->skip_cert_common_name_check) {
esp_transport_ssl_skip_common_name_check(ssl);
}
if (config->reconnect_timeout_ms <= 0) {
client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS;
ESP_LOGW(TAG, "`reconnect_timeout_ms` is not set, or it is less than or equal to zero, using default time out %d (milliseconds)", WEBSOCKET_RECONNECT_TIMEOUT_MS);
} else {
client->wait_timeout_ms = config->reconnect_timeout_ms;
}
esp_transport_handle_t wss = esp_transport_ws_init(ssl);
ESP_WS_CLIENT_MEM_CHECK(TAG, wss, goto _websocket_init_fail);
esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, wss, "wss");
if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) {
asprintf(&client->config->scheme, "wss");
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
}
// configure ssl related parameters
client->config->use_global_ca_store = config->use_global_ca_store;
client->config->cert = config->cert_pem;
client->config->cert_len = config->cert_len;
client->config->client_cert = config->client_cert;
client->config->client_cert_len = config->client_cert_len;
client->config->client_key = config->client_key;
client->config->client_key_len = config->client_key_len;
client->config->skip_cert_common_name_check = config->skip_cert_common_name_check;
client->config->crt_bundle_attach = config->crt_bundle_attach;
if (config->uri) {
if (esp_websocket_client_set_uri(client, config->uri) != ESP_OK) {
@ -434,13 +520,10 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
}
if (client->config->scheme == NULL) {
asprintf(&client->config->scheme, "ws");
asprintf(&client->config->scheme, WS_OVER_TCP_SCHEME);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
}
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, "ws"), goto _websocket_init_fail;)
ESP_WS_CLIENT_ERR_OK_CHECK(TAG, set_websocket_transport_optional_settings(client, "wss"), goto _websocket_init_fail;)
client->keepalive_tick_ms = _tick_get_ms();
client->reconnect_tick_ms = _tick_get_ms();
client->ping_tick_ms = _tick_get_ms();
@ -450,6 +533,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
if (buffer_size <= 0) {
buffer_size = WEBSOCKET_BUFFER_SIZE_BYTE;
}
#ifndef CONFIG_ESP_WS_CLIENT_ENABLE_DYNAMIC_BUFFER
client->rx_buffer = malloc(buffer_size);
ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, {
goto _websocket_init_fail;
@ -458,6 +542,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, {
goto _websocket_init_fail;
});
#endif
client->status_bits = xEventGroupCreate();
ESP_WS_CLIENT_MEM_CHECK(TAG, client->status_bits, {
goto _websocket_init_fail;
@ -566,10 +651,15 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
{
int rlen;
client->payload_offset = 0;
if (esp_websocket_new_buf(client, false) != ESP_OK) {
ESP_LOGE(TAG, "Failed to setup rx buffer");
return ESP_FAIL;
}
do {
rlen = esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms);
if (rlen < 0) {
ESP_LOGE(TAG, "Error read data");
esp_websocket_free_buf(client, false);
return ESP_FAIL;
}
client->payload_len = esp_transport_ws_get_read_payload_len(client->transport);
@ -578,6 +668,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE ) {
ESP_LOGV(TAG, "esp_transport_read timeouts");
esp_websocket_free_buf(client, false);
return ESP_OK;
}
@ -598,7 +689,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
ESP_LOGD(TAG, "Received close frame");
client->state = WEBSOCKET_STATE_CLOSING;
}
esp_websocket_free_buf(client, false);
return ESP_OK;
}
@ -757,6 +848,11 @@ esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client)
ESP_LOGE(TAG, "The client has started");
return ESP_FAIL;
}
if (esp_websocket_client_create_transport(client) != ESP_OK) {
ESP_LOGE(TAG, "Failed to create websocket transport");
return ESP_FAIL;
}
if (xTaskCreate(esp_websocket_client_task, "websocket_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) {
ESP_LOGE(TAG, "Error create websocket task");
return ESP_FAIL;
@ -890,6 +986,10 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
ESP_LOGE(TAG, "Invalid transport");
goto unlock_and_return;
}
if (esp_websocket_new_buf(client, true) != ESP_OK) {
ESP_LOGE(TAG, "Failed to setup tx buffer");
goto unlock_and_return;
}
uint32_t current_opcode = opcode;
while (widx < len || current_opcode) { // allow for sending "current_opcode" only message with len==0
if (need_write > client->buffer_size) {
@ -904,6 +1004,7 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
if (wlen < 0 || (wlen == 0 && need_write != 0)) {
ret = wlen;
ESP_LOGE(TAG, "Network error: esp_transport_write() returned %d, errno=%d", ret, errno);
esp_websocket_free_buf(client, true);
esp_websocket_client_abort_connection(client);
goto unlock_and_return;
}
@ -913,6 +1014,7 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
}
ret = widx;
esp_websocket_free_buf(client, true);
unlock_and_return:
xSemaphoreGiveRecursive(client->lock);
return ret;

View File

@ -1,2 +1,3 @@
idf_component_register(SRCS "websocket_example.c"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -23,6 +23,7 @@
#include "esp_log.h"
#include "esp_websocket_client.h"
#include "esp_event.h"
#include <cJSON.h>
#define NO_DATA_TIMEOUT_SEC 5
@ -74,6 +75,19 @@ static void websocket_event_handler(void *handler_args, esp_event_base_t base, i
} else {
ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr);
}
// If received data contains json structure it succeed to parse
cJSON *root = cJSON_Parse(data->data_ptr);
if (root) {
for (int i = 0 ; i < cJSON_GetArraySize(root) ; i++) {
cJSON *elem = cJSON_GetArrayItem(root, i);
cJSON *id = cJSON_GetObjectItem(elem, "id");
cJSON *name = cJSON_GetObjectItem(elem, "name");
ESP_LOGW(TAG, "Json={'id': '%s', 'name': '%s'}", id->valuestring, name->valuestring);
}
cJSON_Delete(root);
}
ESP_LOGW(TAG, "Total payload length=%d, data_len=%d, current payload offset=%d\r\n", data->payload_len, data->data_len, data->payload_offset);
xTimerReset(shutdown_signal_timer, portMAX_DELAY);

View File

@ -6,6 +6,8 @@ import string
from threading import Event, Thread
import pytest
import sys
import json
import time
from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket
from pytest_embedded import Dut
@ -81,8 +83,33 @@ def test_examples_protocol_websocket(dut):
def test_close(dut):
code = dut.expect(re.compile(b'WEBSOCKET: Received closed message with code=(\\d*)'))[0]
print('Received close frame with code {}'.format(code))
def test_json(dut, websocket):
json_string = """
[
{
"id":"1",
"name":"user1"
},
{
"id":"2",
"name":"user2"
}
]
"""
websocket.send_data(json_string)
data = json.loads(json_string)
match = dut.expect(re.compile(b'Json=([a-zA-Z0-9]*).*')).group(0).decode()[5:]
if match == str(data[0]):
print('Sent message and received message are equal')
else:
raise ValueError('DUT received string do not match sent string, \nexpected: {}\nwith length {}\
\nreceived: {}\nwith length {}'.format(data[0], len(data[0]), match, len(match)))
def test_recv_long_msg(dut, websocket, msg_len, repeats):
send_msg = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(msg_len))
for _ in range(repeats):
@ -121,6 +148,7 @@ def test_examples_protocol_websocket(dut):
test_echo(dut)
# Message length should exceed DUT's buffer size to test fragmentation, default is 1024 byte
test_recv_long_msg(dut, ws, 2000, 3)
test_json(dut, ws)
test_close(dut)
else:
print('DUT connecting to {}'.format(uri))

View File

@ -1,4 +1,4 @@
version: "0.0.1"
version: "0.0.3"
description: esp websocket client
dependencies:
idf:

View File

@ -10,7 +10,7 @@ if(${target} STREQUAL "linux")
set(srcs "mdns.c" ${MDNS_NETWORKING})
else()
set(dependencies lwip console esp_netif)
set(private_dependencies esp_timer)
set(private_dependencies esp_timer esp_wifi)
set(srcs "mdns.c" ${MDNS_NETWORKING} "mdns_console.c")
endif()
@ -20,6 +20,7 @@ idf_component_register(
PRIV_INCLUDE_DIRS "private_include"
REQUIRES ${dependencies}
PRIV_REQUIRES ${private_dependencies})
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
if(CONFIG_ETH_ENABLED)
idf_component_optional_requires(PRIVATE esp_eth)

View File

@ -2,7 +2,7 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "../..")
set(EXTRA_COMPONENT_DIRS "..")
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
list(APPEND EXTRA_COMPONENT_DIRS "../../../common_components/protocol_examples_common")

View File

@ -1,2 +1,3 @@
idf_component_register(SRCS "mdns_example_main.c"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -1,4 +1,4 @@
version: "1.0.3"
version: "1.0.6"
description: mDNS
dependencies:
idf:

View File

@ -20,6 +20,8 @@
#if CONFIG_ETH_ENABLED
#include "esp_eth.h"
#endif
#include "esp_wifi.h"
#ifdef MDNS_ENABLE_DEBUG
void mdns_debug_packet(const uint8_t * data, size_t len);
@ -1684,7 +1686,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
if (!packet) {
return;
}
packet->flags = MDNS_FLAGS_AUTHORITATIVE;
packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE;
packet->distributed = parsed_packet->distributed;
packet->id = parsed_packet->id;
@ -1933,7 +1935,7 @@ static mdns_tx_packet_t * _mdns_create_announce_packet(mdns_if_t tcpip_if, mdns_
if (!packet) {
return NULL;
}
packet->flags = MDNS_FLAGS_AUTHORITATIVE;
packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE;
uint8_t i;
for (i=0; i<len; i++) {
@ -1963,7 +1965,7 @@ static mdns_tx_packet_t * _mdns_create_announce_from_probe(mdns_tx_packet_t * pr
if (!packet) {
return NULL;
}
packet->flags = MDNS_FLAGS_AUTHORITATIVE;
packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE;
mdns_out_answer_t * s = probe->servers;
while (s) {
@ -2003,7 +2005,7 @@ static void _mdns_pcb_send_bye(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco
if (!packet) {
return;
}
packet->flags = MDNS_FLAGS_AUTHORITATIVE;
packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE;
size_t i;
for (i=0; i<len; i++) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, NULL, true, true)) {
@ -3340,13 +3342,13 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
memset(name, 0, sizeof(mdns_name_t));
header.id = _mdns_read_u16(data, MDNS_HEAD_ID_OFFSET);
header.flags.value = _mdns_read_u16(data, MDNS_HEAD_FLAGS_OFFSET);
header.flags = _mdns_read_u16(data, MDNS_HEAD_FLAGS_OFFSET);
header.questions = _mdns_read_u16(data, MDNS_HEAD_QUESTIONS_OFFSET);
header.answers = _mdns_read_u16(data, MDNS_HEAD_ANSWERS_OFFSET);
header.servers = _mdns_read_u16(data, MDNS_HEAD_SERVERS_OFFSET);
header.additional = _mdns_read_u16(data, MDNS_HEAD_ADDITIONAL_OFFSET);
if (header.flags.value == MDNS_FLAGS_AUTHORITATIVE && packet->src_port != MDNS_SERVICE_PORT) {
if (header.flags == MDNS_FLAGS_QR_AUTHORITATIVE && packet->src_port != MDNS_SERVICE_PORT) {
free(parsed_packet);
return;
}
@ -3360,8 +3362,8 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
parsed_packet->tcpip_if = packet->tcpip_if;
parsed_packet->ip_protocol = packet->ip_protocol;
parsed_packet->multicast = packet->multicast;
parsed_packet->authoritative = header.flags.value == MDNS_FLAGS_AUTHORITATIVE;
parsed_packet->distributed = header.flags.value == MDNS_FLAGS_DISTRIBUTED;
parsed_packet->authoritative = (header.flags == MDNS_FLAGS_QR_AUTHORITATIVE);
parsed_packet->distributed = header.flags == MDNS_FLAGS_DISTRIBUTED;
parsed_packet->id = header.id;
esp_netif_ip_addr_copy(&parsed_packet->src, &packet->src);
parsed_packet->src_port = packet->src_port;
@ -3497,7 +3499,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
service = _mdns_get_service_item(name->service, name->proto, NULL);
}
} else {
if (!parsed_packet->authoritative || record_type == MDNS_NS) {
if ((header.flags & MDNS_FLAGS_QUERY_REPSONSE) == 0 || record_type == MDNS_NS) {
//skip this record
continue;
}
@ -6073,11 +6075,11 @@ void mdns_debug_packet(const uint8_t * data, size_t len)
header.additional = _mdns_read_u16(data, MDNS_HEAD_ADDITIONAL_OFFSET);
_mdns_dbg_printf("%s",
(header.flags.value == MDNS_FLAGS_AUTHORITATIVE)?"AUTHORITATIVE\n":
(header.flags.value == MDNS_FLAGS_QR_AUTHORITATIVE)?"AUTHORITATIVE\n":
(header.flags.value == MDNS_FLAGS_DISTRIBUTED)?"DISTRIBUTED\n":
(header.flags.value == 0)?"\n":" "
);
if (header.flags.value && header.flags.value != MDNS_FLAGS_AUTHORITATIVE) {
if (header.flags.value && header.flags.value != MDNS_FLAGS_QR_AUTHORITATIVE) {
_mdns_dbg_printf("0x%04X\n", header.flags.value);
}

View File

@ -338,11 +338,19 @@ size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, c
}
memcpy((uint8_t *)pbt->payload, data, len);
ip_addr_t ip_add_copy;
#if CONFIG_LWIP_IPV6
ip_add_copy.type = ip->type;
memcpy(&(ip_add_copy.u_addr), &(ip->u_addr), sizeof(ip_add_copy.u_addr));
#else
memcpy(&(ip_add_copy.addr), &(ip->u_addr), sizeof(ip_addr_copy.addr));
#endif // CONFIG_LWIP_IPV6
mdns_api_call_t msg = {
.tcpip_if = tcpip_if,
.ip_protocol = ip_protocol,
.pbt = pbt,
.ip = (ip_addr_t *)ip,
.ip = &ip_add_copy,
.port = port
};
tcpip_api_call(_mdns_udp_pcb_write_api, &msg.call);

View File

@ -71,7 +71,9 @@
#define MDNS_ANSWER_A_TTL 120
#define MDNS_ANSWER_AAAA_TTL 120
#define MDNS_FLAGS_AUTHORITATIVE 0x8400
#define MDNS_FLAGS_QUERY_REPSONSE 0x8000
#define MDNS_FLAGS_AUTHORITATIVE 0x0400
#define MDNS_FLAGS_QR_AUTHORITATIVE (MDNS_FLAGS_QUERY_REPSONSE | MDNS_FLAGS_AUTHORITATIVE)
#define MDNS_FLAGS_DISTRIBUTED 0x0200
#define MDNS_NAME_REF 0xC000
@ -211,21 +213,7 @@ typedef enum {
typedef struct {
uint16_t id;
union {
struct {
uint16_t qr :1;
uint16_t opCode :4;
uint16_t aa :1;
uint16_t tc :1;
uint16_t rd :1;
uint16_t ra :1;
uint16_t z :1;
uint16_t ad :1;
uint16_t cd :1;
uint16_t rCode :4;//response/error code
};
uint16_t value;
} flags;
uint16_t flags;
uint16_t questions; //QDCOUNT
uint16_t answers; //ANCOUNT
uint16_t servers; //NSCOUNT

View File

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS "../../../../common_components/protocol_examples_common")
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

View File

@ -1,2 +1,3 @@
idf_component_register(SRCS "main.c" "mdns_test.c"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")