mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-03 13:46:33 +02:00
Compare commits
115 Commits
modem-v0.1
...
websocket-
Author | SHA1 | Date | |
---|---|---|---|
80c3cf0f02 | |||
b3c777ad43 | |||
8ce791e969 | |||
fc7ed90d74 | |||
59e82695e7 | |||
755f16222f | |||
bece6e7045 | |||
46bd32d952 | |||
525c70c0b2 | |||
c4c323666e | |||
19c0455b4d | |||
665c520faf | |||
9118e0f044 | |||
fbdbd550c0 | |||
028be5a8d7 | |||
de7cd72f70 | |||
4a608ec1cd | |||
f0351ff378 | |||
9219ff710a | |||
86aa0b8d39 | |||
1933367f63 | |||
cf697a1a1b | |||
95cf983502 | |||
8a6c320a29 | |||
d1dd6ece38 | |||
36167db336 | |||
d376480766 | |||
e90272c812 | |||
fda070ba39 | |||
6d12d06605 | |||
1455bc0305 | |||
01b4f640d9 | |||
6ab0aea841 | |||
5f2a50f09f | |||
b71c49c277 | |||
f8e3ba7813 | |||
7a5b2d5a7d | |||
42920d7fb5 | |||
2b044f2434 | |||
2b6022c85d | |||
fae2343b19 | |||
17281a515e | |||
aec6a75d40 | |||
a6be8e2e3d | |||
09453e4694 | |||
3b0488cfdc | |||
f21a2f32e0 | |||
a48b0fafe8 | |||
1fcc001ae8 | |||
a41e3383b3 | |||
d0121b964d | |||
f55d8391c9 | |||
fe26b734b5 | |||
f5a26c4d32 | |||
23f6a1d46e | |||
2553d65e64 | |||
67949f94f4 | |||
bfc88ab76c | |||
343fbfdcc9 | |||
4d644954fe | |||
da74a4a489 | |||
f718676083 | |||
13a40d2344 | |||
35d6f9a2c6 | |||
f3a0586663 | |||
325a1933c4 | |||
face03e4e5 | |||
2cb74cf8d0 | |||
d879e82a42 | |||
4f1d31f9b7 | |||
bece4efa09 | |||
8417e232aa | |||
5f0832a0ad | |||
464baeeb83 | |||
5d9ad9cffd | |||
9fbd6e658a | |||
8465b14653 | |||
e7ae0301ae | |||
96498760bf | |||
cf990d1a87 | |||
5299b425e8 | |||
bcb1ab99bd | |||
2c21aa1113 | |||
b9ff1e4e12 | |||
23dbdb584e | |||
1d0cc49c3f | |||
c1249aec17 | |||
2bbcb95e53 | |||
58887170d2 | |||
cc7aa03a37 | |||
15a858b735 | |||
01e2a9c109 | |||
c0021ceeb2 | |||
fec83e5915 | |||
c8c24ed2fc | |||
b380ded5fa | |||
38f6eb963a | |||
2a2d27086f | |||
9dd1bd5ed0 | |||
918db0d2f1 | |||
c1b1330680 | |||
fb7295e91a | |||
8236b3d490 | |||
fb6029b66c | |||
6e34954677 | |||
148a9300a4 | |||
1fb9150bcc | |||
a61e9e2d40 | |||
dc64f862c4 | |||
3332c27978 | |||
84b0dcfea4 | |||
e0e65856f0 | |||
28433de4ad | |||
8f17a90026 | |||
69ad3ea589 |
26
.github/workflows/build-websockets.yml
vendored
Normal file
26
.github/workflows/build-websockets.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
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@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_websocket_client/examples/
|
||||
idf.py build
|
36
.github/workflows/build.yml
vendored
Normal file
36
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
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
|
44
.github/workflows/host-test.yml
vendored
Normal file
44
.github/workflows/host-test.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: Host test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
host_test:
|
||||
name: Build and test
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
lwip_contrib: contrib-2.1.0
|
||||
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install -y gcc-8 g++-8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
|
||||
export LWIP_PATH=`pwd`/${{ env.lwip }}
|
||||
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
|
||||
wget --no-verbose ${lwip_uri}/${lwip}.zip
|
||||
unzip -oq ${lwip}.zip
|
||||
wget --no-verbose ${lwip_uri}/${lwip_contrib}.zip
|
||||
unzip -oq ${lwip_contrib}.zip
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/linux_modem
|
||||
idf.py build
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/test/host_test
|
||||
idf.py build
|
||||
./build/host_modem_test.elf -r junit -o junit.xml
|
||||
|
||||
- name: Publish Results
|
||||
uses: EnricoMi/publish-unit-test-result-action@v1
|
||||
if: always()
|
||||
with:
|
||||
files: esp-protocols/components/esp_modem/test/host_test/junit.xml
|
39
.github/workflows/publish-docs-component-websockets.yml
vendored
Normal file
39
.github/workflows/publish-docs-component-websockets.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
name: Docs and Publish Websockets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
docs_build:
|
||||
name: Docs-Build-And-Upload
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate docs
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip git
|
||||
sudo git clone https://github.com/espressif/esp-idf
|
||||
python -m pip install breathe recommonmark
|
||||
python -m pip install -r esp-idf/docs/requirements.txt
|
||||
cd $GITHUB_WORKSPACE/components/esp_websocket_client/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/esp_websocket_client
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/esp_websocket_client
|
||||
cd $GITHUB_WORKSPACE/docs
|
||||
touch .nojekyll
|
||||
echo '<a href="esp_websocket_client/index.html">esp-websocket-client</a>' >> index.html
|
||||
|
||||
- name: Deploy generated docs.
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.5
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs
|
45
.github/workflows/publish-docs-component.yml
vendored
Normal file
45
.github/workflows/publish-docs-component.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: Docs and Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
docs_build:
|
||||
name: Docs-Build-And-Upload
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate docs
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip
|
||||
python -m pip install breathe recommonmark
|
||||
cd $GITHUB_WORKSPACE/components/esp_modem/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/esp_modem
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/esp_modem
|
||||
cd $GITHUB_WORKSPACE/docs
|
||||
touch .nojekyll
|
||||
echo '<a href="esp_modem/index.html">esp-modem</a>' > index.html
|
||||
|
||||
- name: Upload components to component service
|
||||
uses: espressif/github-actions/upload_components@master
|
||||
with:
|
||||
directories: "components/esp_modem"
|
||||
name: "esp_modem"
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
||||
- name: Deploy generated docs
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.5
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs
|
21
.github/workflows/sync_issues.yml
vendored
Normal file
21
.github/workflows/sync_issues.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Sync issue comments to JIRA
|
||||
|
||||
# This workflow will be triggered when new issue is created
|
||||
# or a new issue/PR comment is created
|
||||
on: [issues, issue_comment]
|
||||
|
||||
jobs:
|
||||
sync_issue_comments_to_jira:
|
||||
name: Sync Issue Comments to Jira
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Sync issue comments to JIRA
|
||||
uses: espressif/github-actions/sync_issues_to_jira@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
JIRA_PASS: ${{ secrets.JIRA_PASS }}
|
||||
JIRA_PROJECT: IDFGH
|
||||
JIRA_COMPONENT: esp-protocols
|
||||
JIRA_URL: ${{ secrets.JIRA_URL }}
|
||||
JIRA_USER: ${{ secrets.JIRA_USER }}
|
11
README.md
11
README.md
@ -1 +1,10 @@
|
||||
# Collection of components for ESP-IDF
|
||||
# Collection of protocol components for ESP-IDF
|
||||
|
||||
[Documentation of esp-protocol](https://espressif.github.io/esp-protocols)
|
||||
|
||||
## Components
|
||||
|
||||
### esp_modem
|
||||
|
||||
* Brief introduction [README](components/esp_modem/README.md)
|
||||
* Full html [documentation](https://espressif.github.io/esp-protocols/esp_modem/index.html)
|
||||
|
9
components/esp_modem/.gitignore
vendored
9
components/esp_modem/.gitignore
vendored
@ -51,9 +51,9 @@ tools/unit-test-app/test_configs
|
||||
log_ut_cmake
|
||||
|
||||
# test application build files
|
||||
tools/test_apps/**/build
|
||||
tools/test_apps/**/sdkconfig
|
||||
tools/test_apps/**/sdkconfig.old
|
||||
test/**/build
|
||||
test/**/sdkconfig
|
||||
test/**/sdkconfig.old
|
||||
|
||||
# IDF monitor test
|
||||
tools/test_idf_monitor/outputs
|
||||
@ -88,3 +88,6 @@ build
|
||||
|
||||
# lock files for examples and components
|
||||
dependencies.lock
|
||||
|
||||
# ignore generated docs
|
||||
docs/html
|
@ -7,6 +7,7 @@ if(${target} STREQUAL "linux")
|
||||
set(dependencies esp_system_protocols_linux)
|
||||
else()
|
||||
set(platform_srcs src/esp_modem_primitives_freertos.cpp
|
||||
src/esp_modem_api_target.cpp
|
||||
src/esp_modem_uart.cpp
|
||||
src/esp_modem_term_uart.cpp
|
||||
src/esp_modem_netif.cpp)
|
||||
@ -22,6 +23,8 @@ set(srcs ${platform_srcs}
|
||||
"src/esp_modem_cmux.cpp"
|
||||
"src/esp_modem_command_library.cpp"
|
||||
"src/esp_modem_term_fs.cpp"
|
||||
"src/esp_modem_vfs_uart_creator.cpp"
|
||||
"src/esp_modem_vfs_socket_creator.cpp"
|
||||
"src/esp_modem_modules.cpp")
|
||||
|
||||
set(include_dirs "include")
|
||||
@ -31,7 +34,16 @@ idf_component_register(SRCS "${srcs}"
|
||||
PRIV_INCLUDE_DIRS private_include
|
||||
REQUIRES ${dependencies})
|
||||
|
||||
target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17)
|
||||
|
||||
# If CMake doesn't know C++17 features, set it manually via comile options
|
||||
# esp-modem component requires C++17 internally, but older CMake (< 3.8, but still supported in IDF)
|
||||
# doesn't support target_compile_features() for cxx_std_17.
|
||||
get_property(cxx_known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
|
||||
if ("cxx_std_17" IN_LIST cxx_known_features)
|
||||
target_compile_features(${COMPONENT_LIB} PRIVATE cxx_std_17)
|
||||
else()
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-std=gnu++17")
|
||||
endif()
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64
|
||||
|
@ -1,6 +1,6 @@
|
||||
# ESP MODEM
|
||||
|
||||
The `esp-modem` component is a managed component for `esp-idf` that could be used for communication with GSM/LTE modems
|
||||
The `esp-modem` component is a managed component for `esp-idf` that is used for communication with GSM/LTE modems
|
||||
that support AT commands and PPP protocol as a network interface.
|
||||
|
||||
## Examples
|
||||
@ -16,4 +16,4 @@ Get started with one of the examples:
|
||||
## Documentation
|
||||
|
||||
* Continue with esp-modem [brief overview](docs/README.md)
|
||||
* View the full [html documentation ](docs/html/index.html)
|
||||
* View the full [html documentation](https://espressif.github.io/esp-protocols/esp_modem/index.html)
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 26 KiB |
@ -36,11 +36,11 @@ After the object is created, the application interaction with the DCE is in
|
||||
* switching between data and command mode
|
||||
|
||||
### DTE
|
||||
Is an abstraction of the connected interface. Current implementation supports only UART
|
||||
Is an abstraction of the physical interface connected to the modem. Current implementation supports only UART
|
||||
|
||||
### PPP
|
||||
### PPP netif
|
||||
|
||||
Is used to connect the specific network interface to the modem data mode. Currently implementation supports only PPPoS protocol.
|
||||
Is used to attach the specific network interface to a network communication protocol used by the modem. Currently implementation supports only PPPoS protocol.
|
||||
|
||||
### Module
|
||||
|
||||
@ -48,7 +48,7 @@ Abstraction of the specific modem device. Currently the component supports SIM80
|
||||
|
||||
## Use cases
|
||||
|
||||
Users could interact with the esp-modem using the DCE's interface, to basically
|
||||
Users interact with the esp-modem using the DCE's interface, to basically
|
||||
* Switch between command and data mode to connect to the internet via cellular network.
|
||||
* Send various commands to the device (e.g. send SMS)
|
||||
|
||||
@ -57,16 +57,15 @@ IP address changes.
|
||||
|
||||
Common use cases of the esp-modem are also listed as the examples:
|
||||
* `examples/pppos_client` -- simple client which reads some module properties and switches to the data mode to connect to a public mqtt broker.
|
||||
* `examples/modem_console` -- is an example to exercise all possible modules commands in a console application.
|
||||
* `examples/ap_to_pppos` -- this example focuses on the network connectivity of the esp-modem and provides a WiFi AP
|
||||
that forwards packets (and uses NAT) to and from the PPPoS connection.
|
||||
* `examples/modem_console` -- is an example to exercise all possible module commands in a console application.
|
||||
* `examples/ap_to_pppos` -- this example focuses on the network connectivity of the esp-modem and provides a WiFi AP that forwards packets (and uses NAT) to and from the PPPoS connection.
|
||||
|
||||
## Extensibility
|
||||
|
||||
### CMUX
|
||||
|
||||
Implementation of virtual terminals is an experimental feature, which allows users to also issue commands in the data mode,
|
||||
after creating multiple virtual terminals, designating some of them solely to the data mode, while other to command mode.
|
||||
after creating multiple virtual terminals, designating some of them solely to data mode, others solely to command mode.
|
||||
|
||||
### DTE's
|
||||
|
||||
@ -74,6 +73,6 @@ Currently we support only UART, but modern modules support other communication i
|
||||
|
||||
### Other devices
|
||||
|
||||
Adding a new device is a must-have requirement for the esp-component. Different modules support different commands,
|
||||
Adding a new device is a must-have requirement for the esp-modem component. Different modules support different commands,
|
||||
or some commands might have a different implementation. Adding a new device means to provide a new implementation
|
||||
as a class derived from `GenericModule`, where we could add new commands or modify the existing ones.
|
||||
|
@ -19,14 +19,15 @@ All the functionality is provided by the DCE factory
|
||||
.. doxygengroup:: ESP_MODEM_DCE_FACTORY
|
||||
:members:
|
||||
|
||||
.. _create_custom_module:
|
||||
|
||||
Create custom module
|
||||
--------------------
|
||||
|
||||
Creating a custom module is necessary if the application needs to use a specific device that is not supported
|
||||
and their commands differ from any of the supported devices. In this case it is recommended to define a new class
|
||||
representing this specific device and derive from the :cpp:class:`GenericModule`. In order to instantiate
|
||||
the appropriate DCE of this module, application could use :ref:`the DCE factory<dce_factory>`, but build the DCE with
|
||||
representing this specific device and derive from the :cpp:class:`esp_modem::GenericModule`. In order to instantiate
|
||||
the appropriate DCE of this module, application could use :ref:`the DCE factory<dce_factory>`, and build the DCE with
|
||||
the specific module, using :cpp:func:`esp_modem::dce_factory::Factory::build`.
|
||||
|
||||
Please refer to the implementation of the existing modules.
|
||||
@ -41,7 +42,7 @@ Create new communication interface
|
||||
In order to connect to a device using an unsupported interface (e.g. SPI or I2C), it is necessary to implement
|
||||
a custom DTE object and supply it into :ref:`the DCE factory<dce_factory>`. The DCE is typically created in two steps:
|
||||
|
||||
- Define and create the corresponding terminal, which can communicate on the custom interface. This terminal should support basic IO methods defined in :cpp:class:`esp_modem::Terminal` and derive from it.
|
||||
- Define and create the corresponding terminal, which communicates on the custom interface. This terminal should support basic IO methods defined in :cpp:class:`esp_modem::Terminal` and derive from it.
|
||||
- Create the DTE which uses the custom Terminal
|
||||
|
||||
Please refer to the implementation of the existing UART DTE.
|
||||
|
@ -1,15 +1,15 @@
|
||||
.. _c_api:
|
||||
|
||||
API Guide for C interface
|
||||
=========================
|
||||
C API Documentation
|
||||
===================
|
||||
|
||||
|
||||
C API is very simple and consist of these two basic parts:
|
||||
The C API is very simple and consist of these two basic parts:
|
||||
|
||||
- :ref:`lifecycle_api`
|
||||
- :ref:`modem_commands`
|
||||
|
||||
Typical application workflow is to:
|
||||
The Typical application workflow is to:
|
||||
|
||||
- Create a DCE instance (using :cpp:func:`esp_modem_new`)
|
||||
- Call specific functions to issue AT commands (:ref:`modem_commands`)
|
||||
@ -41,6 +41,9 @@ Modem commands
|
||||
|
||||
These functions are the actual commands to communicate with the modem using AT command interface.
|
||||
|
||||
Note that the functions which implement AT commands returning textual values use plain ``char *``
|
||||
pointer as the return value. The API expects the output data to point to user allocated space of at least
|
||||
``ESP_MODEM_C_API_STR_MAX`` (64 by default) bytes, it also truncates the output data to this size.
|
||||
|
||||
.. doxygenfile:: esp_modem_api_commands.h
|
||||
|
||||
|
@ -16,7 +16,8 @@ copyright = u'2016 - 2021, Espressif Systems (Shanghai) Co., Ltd'
|
||||
# for a list of supported languages.
|
||||
language = 'en'
|
||||
|
||||
extensions = ['breathe']
|
||||
extensions = ['breathe', 'recommonmark']
|
||||
|
||||
|
||||
breathe_projects = {'esp_modem': 'xml'}
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
|
||||
- :cpp:func:`esp_modem::DCE::sync`
|
||||
- :cpp:func:`esp_modem::DCE::get_operator_name`
|
||||
- :cpp:func:`esp_modem::DCE::store_profile`
|
||||
- :cpp:func:`esp_modem::DCE::set_pin`
|
||||
- :cpp:func:`esp_modem::DCE::read_pin`
|
||||
- :cpp:func:`esp_modem::DCE::set_echo`
|
||||
- :cpp:func:`esp_modem::DCE::sms_txt_mode`
|
||||
- :cpp:func:`esp_modem::DCE::sms_character_set`
|
||||
- :cpp:func:`esp_modem::DCE::send_sms`
|
||||
- :cpp:func:`esp_modem::DCE::resume_data_mode`
|
||||
- :cpp:func:`esp_modem::DCE::set_pdp_context`
|
||||
- :cpp:func:`esp_modem::DCE::set_command_mode`
|
||||
- :cpp:func:`esp_modem::DCE::set_cmux`
|
||||
- :cpp:func:`esp_modem::DCE::get_imsi`
|
||||
- :cpp:func:`esp_modem::DCE::get_imei`
|
||||
- :cpp:func:`esp_modem::DCE::get_module_name`
|
||||
- :cpp:func:`esp_modem::DCE::set_data_mode`
|
||||
- :cpp:func:`esp_modem::DCE::get_signal_quality`
|
||||
- :cpp:func:`esp_modem::DCE::set_flow_control`
|
||||
- :cpp:func:`esp_modem::DCE::hang_up`
|
||||
- :cpp:func:`esp_modem::DCE::get_battery_status`
|
||||
- :cpp:func:`esp_modem::DCE::power_down`
|
||||
- :cpp:func:`esp_modem::DCE::reset`
|
||||
- :cpp:func:`esp_modem::DCE::set_baud`
|
@ -1,99 +0,0 @@
|
||||
// cat ../include/generate/esp_modem_command_declare.inc | clang -E -P -CC -xc -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > c_api.h
|
||||
// cat ../include/generate/esp_modem_command_declare.inc | clang -E -P -xc -I../include -DGENERATE_DOCS -DGENERATE_RST_LINKS - | sed 's/NL/\n/g' > cxx_api_links.rst
|
||||
|
||||
// call parametrs by names for documentation
|
||||
|
||||
|
||||
// --- DCE command documentation starts here ---
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_sync (); /**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_get_operator_name (char* name); /**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_store_profile (); /**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/command_result esp_modem_set_pin (const char* pin); /**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_read_pin (bool* pin_ok); /**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_set_echo (const bool echo_on); /**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_sms_txt_mode (const bool txt); /**
|
||||
* @brief Sets the default (GSM) charater set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_sms_character_set (); /**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_send_sms (const char* number, const char* message); /**
|
||||
* @brief Resumes data mode (Switches back to th data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_resume_data_mode (); /**
|
||||
* @brief Sets php context
|
||||
* @param[in] x PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_set_pdp_context (struct PdpContext* x); /**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_set_command_mode (); /**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_set_cmux (); /**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_get_imsi (char* imsi); /**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_get_imei (char* imei); /**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_get_module_name (char* name); /**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_set_data_mode (); /**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_get_signal_quality (int* rssi, int* ber); /**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_set_flow_control (int dce_flow, int dte_flow); /**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_hang_up (); /**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_get_battery_status (int* voltage, int* bcs, int* bcl); /**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_power_down (); /**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_reset (); /**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result esp_modem_set_baud (int baud);
|
@ -1,111 +0,0 @@
|
||||
// cat ../include/generate/esp_modem_command_declare.inc | clang -E -P -CC -xc -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > c_api.h
|
||||
// cat ../include/generate/esp_modem_command_declare.inc | clang -E -P -xc -I../include -DGENERATE_DOCS -DGENERATE_RST_LINKS - | sed 's/NL/\n/g' > cxx_api_links.rst
|
||||
|
||||
// call parametrs by names for documentation
|
||||
|
||||
|
||||
// --- DCE command documentation starts here ---
|
||||
|
||||
class esp_modem::DCE: public DCE_T<GenericModule> {
|
||||
public:
|
||||
using DCE_T<GenericModule>::DCE_T;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends the initial AT sequence to sync up with the device
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result sync (); /**
|
||||
* @brief Reads the operator name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result get_operator_name (std::string& name); /**
|
||||
* @brief Stores current user profile
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result store_profile (); /**
|
||||
* @brief Sets the supplied PIN code
|
||||
* @param[in] pin Pin
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/command_result set_pin (const std::string& pin); /**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result read_pin (bool& pin_ok); /**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result set_echo (const bool echo_on); /**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result sms_txt_mode (const bool txt); /**
|
||||
* @brief Sets the default (GSM) charater set
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result sms_character_set (); /**
|
||||
* @brief Sends SMS message in txt mode
|
||||
* @param[in] number Phone number to send the message to
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result send_sms (const std::string& number, const std::string& message); /**
|
||||
* @brief Resumes data mode (Switches back to th data mode, which was temporarily suspended)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result resume_data_mode (); /**
|
||||
* @brief Sets php context
|
||||
* @param[in] x PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result set_pdp_context (PdpContext& x); /**
|
||||
* @brief Switches to the command mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result set_command_mode (); /**
|
||||
* @brief Switches to the CMUX mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result set_cmux (); /**
|
||||
* @brief Reads the IMSI number
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result get_imsi (std::string& imsi); /**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result get_imei (std::string& imei); /**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result get_module_name (std::string& name); /**
|
||||
* @brief Sets the modem to data mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result set_data_mode (); /**
|
||||
* @brief Get Signal quality
|
||||
* @param[out] rssi signal strength indication
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result get_signal_quality (int& rssi, int& ber); /**
|
||||
* @brief Sets HW control flow
|
||||
* @param[in] dce_flow 0=none, 2=RTS hw flow control of DCE
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result set_flow_control (int dce_flow, int dte_flow); /**
|
||||
* @brief Hangs up current data call
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result hang_up (); /**
|
||||
* @brief Get voltage levels of modem power up circuitry
|
||||
* @param[out] voltage Current status in mV
|
||||
* @param[out] bcs charge status (-1-Not available, 0-Not charging, 1-Charging, 2-Charging done)
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result get_battery_status (int& voltage, int& bcs, int& bcl); /**
|
||||
* @brief Power down the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result power_down (); /**
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result reset (); /**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ command_result set_baud (int baud);
|
||||
};
|
@ -19,5 +19,5 @@ doxygen
|
||||
# Generate the docs
|
||||
python -u -m sphinx.cmd.build -b html . html
|
||||
|
||||
# Cleanup the doxygen xml's
|
||||
rm -rf xml
|
||||
# Cleanup the doxygen xml's and temporary headers
|
||||
rm -rf xml esp_modem_api_commands.h esp_modem_dce.hpp cxx_api_links.rst
|
||||
|
@ -9,6 +9,13 @@ The esp-modem actually implements the DCE class, which in turn aggregates these
|
||||
- :ref:`Netif<netif_impl>` to provide the network connectivity
|
||||
- :ref:`Module<module_impl>` to define the specific command library
|
||||
|
||||
Developers would typically have to
|
||||
|
||||
* Add support for a new module
|
||||
* Implement a generic (common for all modules) AT command
|
||||
|
||||
This is explained in the :ref:`Module<module_impl>` section, as :ref:`Adding new module or command<module_addition>`
|
||||
|
||||
------------
|
||||
|
||||
.. doxygengroup:: ESP_MODEM_DCE
|
||||
@ -63,6 +70,36 @@ Module abstraction
|
||||
.. doxygengroup:: ESP_MODEM_MODULE
|
||||
:members:
|
||||
|
||||
.. _module_addition:
|
||||
|
||||
Adding new devices
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To support a new module, developers would have to implement a new class derived from :cpp:class:`esp_modem::GenericModule` the same way
|
||||
as it is described in the :ref:`Advanced user manual<create_custom_module>`. The only difference is that the new class (and factory extension)
|
||||
would be available in the esp_modem code base.
|
||||
|
||||
Implement a new generic command
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Adding a generic command, i.e. the command that is shared for all modules and is included in the :cpp:class:`esp_modem::GenericModule`,
|
||||
has to be declared first in the ``include/generate/esp_modem_command_declare.inc`` file, which is the single source
|
||||
of supported command definitions, that is used in:
|
||||
|
||||
* public C API
|
||||
* public CPP API
|
||||
* generated documentation
|
||||
* implementation of the command
|
||||
|
||||
Therefore, a care must be taken, to correctly specify all parameters and types, especially:
|
||||
|
||||
* Keep number of parameters low (<= 6, used in preprocessor's forwarding to the command library)
|
||||
* Use macros to specify parameter types (as they are used both from C and C++ with different underlying types)
|
||||
* Parameter names are used only for clarity and documentation, they get expanded to numbered arguments.
|
||||
|
||||
Please use the following pattern: ``INT_IN(p1, baud)``, meaning that the parameter is an input integer,
|
||||
human readable argument name is ``baud``, it's the first argument, so expands to ``p1`` (second argument would be ``p2``, etc)
|
||||
|
||||
Command library
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -15,3 +15,7 @@ By default, this example simply connects to the PPP server using a supported dev
|
||||
This example however, doesn't rely on sending specific AT commands, just the bare minimum to setup the cellular network.
|
||||
Thus, if the `EXAMPLE_USE_MINIMAL_DCE` option is enabled, we directly inherit from the `ModuleIf` and implement only the basic commands.
|
||||
Also, to demonstrate the dce_factory functionality, a new `NetDCE_Factory` is implemented for creating the network module and the DCE.
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.2`, since is uses NAPT feature.
|
@ -31,9 +31,16 @@ menu "Example Configuration"
|
||||
help
|
||||
Set APN (Access Point Name), a logical name to choose data network
|
||||
|
||||
config EXAMPLE_NEED_SIM_PIN
|
||||
bool "SIM PIN needed"
|
||||
default n
|
||||
help
|
||||
Enable to set SIM PIN before starting the example
|
||||
|
||||
config EXAMPLE_SIM_PIN
|
||||
string "Set SIM PIN"
|
||||
default "1234"
|
||||
depends on EXAMPLE_NEED_SIM_PIN
|
||||
help
|
||||
Pin to unlock the SIM
|
||||
|
||||
|
@ -32,36 +32,32 @@ static const int DISCONNECT_BIT = BIT1;
|
||||
static void on_ip_event(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_base == IP_EVENT) {
|
||||
ESP_LOGD(TAG, "IP event! %d", event_id);
|
||||
if (event_id == IP_EVENT_PPP_GOT_IP) {
|
||||
esp_netif_dns_info_t dns_info;
|
||||
ESP_LOGD(TAG, "IP event! %d", event_id);
|
||||
if (event_id == IP_EVENT_PPP_GOT_IP) {
|
||||
esp_netif_dns_info_t dns_info;
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
esp_netif_t *netif = event->esp_netif;
|
||||
|
||||
ESP_LOGI(TAG, "Modem Connect to PPP Server");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "IP : " IPSTR, IP2STR(&event->ip_info.ip));
|
||||
ESP_LOGI(TAG, "Netmask : " IPSTR, IP2STR(&event->ip_info.netmask));
|
||||
ESP_LOGI(TAG, "Gateway : " IPSTR, IP2STR(&event->ip_info.gw));
|
||||
esp_netif_get_dns_info(netif, 0, &dns_info);
|
||||
ESP_LOGI(TAG, "Name Server1: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
|
||||
esp_netif_get_dns_info(netif, 1, &dns_info);
|
||||
ESP_LOGI(TAG, "Name Server2: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
|
||||
xEventGroupSetBits(event_group, CONNECT_BIT);
|
||||
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
esp_netif_t *netif = event->esp_netif;
|
||||
|
||||
ESP_LOGI(TAG, "Modem Connect to PPP Server");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "IP : " IPSTR, IP2STR(&event->ip_info.ip));
|
||||
ESP_LOGI(TAG, "Netmask : " IPSTR, IP2STR(&event->ip_info.netmask));
|
||||
ESP_LOGI(TAG, "Gateway : " IPSTR, IP2STR(&event->ip_info.gw));
|
||||
esp_netif_get_dns_info(netif, 0, &dns_info);
|
||||
ESP_LOGI(TAG, "Name Server1: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
|
||||
esp_netif_get_dns_info(netif, 1, &dns_info);
|
||||
ESP_LOGI(TAG, "Name Server2: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~~~~");
|
||||
xEventGroupSetBits(event_group, CONNECT_BIT);
|
||||
|
||||
ESP_LOGI(TAG, "GOT ip event!!!");
|
||||
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
|
||||
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
|
||||
xEventGroupSetBits(event_group, DISCONNECT_BIT);
|
||||
} else if (event_id == IP_EVENT_GOT_IP6) {
|
||||
ESP_LOGI(TAG, "GOT IPv6 event!");
|
||||
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
|
||||
ESP_LOGI(TAG, "Got IPv6 address " IPV6STR, IPV62STR(event->ip6_info.ip));
|
||||
}
|
||||
ESP_LOGI(TAG, "GOT ip event!!!");
|
||||
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
|
||||
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
|
||||
xEventGroupSetBits(event_group, DISCONNECT_BIT);
|
||||
} else if (event_id == IP_EVENT_GOT_IP6) {
|
||||
ESP_LOGI(TAG, "GOT IPv6 event!");
|
||||
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
|
||||
ESP_LOGI(TAG, "Got IPv6 address " IPV6STR, IPV62STR(event->ip6_info.ip));
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +89,6 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base,
|
||||
|
||||
void wifi_init_softap(void)
|
||||
{
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
|
@ -25,6 +25,7 @@ esp_err_t modem_init_network(esp_netif_t *netif)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_NEED_SIM_PIN
|
||||
// configure the PIN
|
||||
bool pin_ok = false;
|
||||
if (esp_modem_read_pin(dce, &pin_ok) == ESP_OK && pin_ok == false) {
|
||||
@ -34,6 +35,7 @@ esp_err_t modem_init_network(esp_netif_t *netif)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_NEED_SIM_PIN
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -19,40 +19,28 @@ using namespace esp_modem;
|
||||
using namespace esp_modem::dce_factory;
|
||||
|
||||
class NetModule;
|
||||
typedef DCE_T<NetModule> NetDCE;
|
||||
|
||||
/**
|
||||
* @brief Local network object used to setup PPP network
|
||||
*/
|
||||
class PPPNetwork {
|
||||
public:
|
||||
esp_err_t init(esp_netif_t *netif, const std::string& apn, const std::string &pin_number);
|
||||
void deinit();
|
||||
NetDCE * get_dce();
|
||||
private:
|
||||
NetDCE *dce;
|
||||
};
|
||||
using NetDCE = DCE_T<NetModule>;
|
||||
|
||||
/**
|
||||
* @brief The PPP network is a singleton, allocate statically here
|
||||
*/
|
||||
static PPPNetwork ppp_network;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Custom factory for creating NetDCE and NetModule
|
||||
*/
|
||||
class NetDCE_Factory: public Factory {
|
||||
public:
|
||||
template <typename T, typename ...Args>
|
||||
static DCE_T<T>* create(const config *cfg, Args&&... args)
|
||||
template <typename Module, typename ...Args>
|
||||
static DCE_T<Module> *create(const config *cfg, Args &&... args)
|
||||
{
|
||||
return build_generic_DCE<T>(cfg, std::forward<Args>(args)...);
|
||||
return build_generic_DCE<Module>(cfg, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
static std::shared_ptr<T> create_module(const config *cfg, Args&&... args)
|
||||
template <typename Module, typename ...Args>
|
||||
static std::shared_ptr<Module> create_module(const config *cfg, Args &&... args)
|
||||
{
|
||||
return build_shared_module<T>(cfg, std::forward<Args>(args)...);
|
||||
return build_shared_module<Module>(cfg, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
@ -65,42 +53,48 @@ public:
|
||||
class NetModule: public ModuleIf {
|
||||
public:
|
||||
explicit NetModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config *cfg):
|
||||
dte(std::move(dte)), apn(std::string(cfg->apn)) {}
|
||||
dte(std::move(dte)), apn(std::string(cfg->apn)) {}
|
||||
|
||||
bool setup_data_mode() override
|
||||
[[nodiscard]] bool setup_data_mode() override
|
||||
{
|
||||
PdpContext pdp(apn);
|
||||
if (set_pdp_context(pdp) != command_result::OK)
|
||||
if (set_pdp_context(pdp) != command_result::OK) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_mode(modem_mode mode) override
|
||||
{
|
||||
if (mode == modem_mode::DATA_MODE) {
|
||||
if (set_data_mode() != command_result::OK)
|
||||
switch (mode) {
|
||||
case esp_modem::modem_mode::DATA_MODE:
|
||||
if (set_data_mode() != command_result::OK) {
|
||||
return resume_data_mode() == command_result::OK;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (mode == modem_mode::COMMAND_MODE) {
|
||||
case esp_modem::modem_mode::COMMAND_MODE:
|
||||
return set_command_mode() == command_result::OK;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool init(const std::string& pin)
|
||||
[[maybe_unused]] bool init_sim(const std::string &pin)
|
||||
{
|
||||
// switch to command mode (in case we were in PPP mode)
|
||||
static_cast<void>(set_command_mode()); // ignore the potential failure, as we might be in command mode after startup
|
||||
bool is_pin_ok;
|
||||
if (read_pin(is_pin_ok) != command_result::OK)
|
||||
if (read_pin(is_pin_ok) != command_result::OK) {
|
||||
return false;
|
||||
}
|
||||
if (!is_pin_ok) {
|
||||
if (set_pin(pin) != command_result::OK)
|
||||
if (set_pin(pin) != command_result::OK) {
|
||||
return false;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
if (read_pin(is_pin_ok) != command_result::OK || !is_pin_ok)
|
||||
if (read_pin(is_pin_ok) != command_result::OK || !is_pin_ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -109,68 +103,83 @@ private:
|
||||
std::shared_ptr<DTE> dte;
|
||||
std::string apn;
|
||||
|
||||
[[nodiscard]] command_result set_pdp_context(PdpContext& pdp) { return dce_commands::set_pdp_context(dte.get(),pdp); }
|
||||
[[nodiscard]] command_result set_pin(const std::string &pin) { return dce_commands::set_pin(dte.get(), pin); }
|
||||
[[nodiscard]] command_result read_pin(bool& pin_ok) { return dce_commands::read_pin(dte.get(), pin_ok); }
|
||||
[[nodiscard]] command_result set_data_mode() { return dce_commands::set_data_mode(dte.get()); }
|
||||
[[nodiscard]] command_result resume_data_mode() { return dce_commands::resume_data_mode(dte.get()); }
|
||||
[[nodiscard]] command_result set_command_mode() { return dce_commands::set_command_mode(dte.get()); }
|
||||
[[nodiscard]] command_result set_pdp_context(PdpContext &pdp)
|
||||
{
|
||||
return dce_commands::set_pdp_context(dte.get(), pdp);
|
||||
}
|
||||
[[nodiscard]] command_result set_pin(const std::string &pin)
|
||||
{
|
||||
return dce_commands::set_pin(dte.get(), pin);
|
||||
}
|
||||
[[nodiscard]] command_result read_pin(bool &pin_ok)
|
||||
{
|
||||
return dce_commands::read_pin(dte.get(), pin_ok);
|
||||
}
|
||||
[[nodiscard]] command_result set_data_mode()
|
||||
{
|
||||
return dce_commands::set_data_mode(dte.get());
|
||||
}
|
||||
[[nodiscard]] command_result resume_data_mode()
|
||||
{
|
||||
return dce_commands::resume_data_mode(dte.get());
|
||||
}
|
||||
[[nodiscard]] command_result set_command_mode()
|
||||
{
|
||||
return dce_commands::set_command_mode(dte.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
esp_err_t PPPNetwork::init(esp_netif_t *netif, const std::string& apn, const std::string &pin_number)
|
||||
/**
|
||||
* @brief Implement the C-API for the AP-2-PPP functionality
|
||||
*/
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Local network object used to setup PPP network
|
||||
*/
|
||||
NetDCE *dce = nullptr;
|
||||
|
||||
extern "C" esp_err_t modem_init_network(esp_netif_t *netif)
|
||||
{
|
||||
// configure
|
||||
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||||
dte_config.uart_config.rx_buffer_size = 16384;
|
||||
dte_config.uart_config.tx_buffer_size = 2048;
|
||||
esp_modem_dce_config dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(apn.c_str());
|
||||
esp_modem_dce_config dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
|
||||
|
||||
// create DTE and minimal network DCE
|
||||
auto uart_dte = create_uart_dte(&dte_config);
|
||||
|
||||
// create the specific device (and initialize it)
|
||||
auto dev = NetDCE_Factory::create_module<NetModule>(&dce_config, uart_dte, netif);
|
||||
if (!dev->init(pin_number))
|
||||
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
|
||||
if (!dev->init_sim(CONFIG_EXAMPLE_SIM_PIN)) {
|
||||
return ESP_FAIL;
|
||||
|
||||
}
|
||||
#endif
|
||||
// now create the DCE from our already existent device
|
||||
dce = NetDCE_Factory::create<NetModule>(&dce_config, uart_dte, netif, dev);
|
||||
if (dce == nullptr)
|
||||
if (dce == nullptr) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void PPPNetwork::deinit()
|
||||
extern "C" void modem_start_network()
|
||||
{
|
||||
dce->set_mode(esp_modem::modem_mode::DATA_MODE);
|
||||
}
|
||||
|
||||
extern "C" void modem_stop_network()
|
||||
{
|
||||
dce->set_mode(esp_modem::modem_mode::COMMAND_MODE);
|
||||
}
|
||||
|
||||
extern "C" void modem_deinit_network()
|
||||
{
|
||||
free(dce);
|
||||
dce = nullptr;
|
||||
}
|
||||
|
||||
NetDCE *PPPNetwork::get_dce()
|
||||
{
|
||||
return dce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implement the C-API for the AP-2-PPP functionality
|
||||
*/
|
||||
extern "C" esp_err_t modem_init_network(esp_netif_t *netif)
|
||||
{
|
||||
return ppp_network.init(netif, CONFIG_EXAMPLE_MODEM_PPP_APN, CONFIG_EXAMPLE_SIM_PIN);
|
||||
}
|
||||
|
||||
extern "C" void modem_start_network()
|
||||
{
|
||||
ppp_network.get_dce()->set_mode(esp_modem::modem_mode::DATA_MODE);
|
||||
}
|
||||
|
||||
extern "C" void modem_stop_network()
|
||||
{
|
||||
ppp_network.get_dce()->set_mode(esp_modem::modem_mode::COMMAND_MODE);
|
||||
}
|
||||
|
||||
extern "C" void modem_deinit_network()
|
||||
{
|
||||
ppp_network.deinit();
|
||||
}
|
||||
}
|
@ -7,8 +7,7 @@
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _NETWORK_DCE_H_
|
||||
#define _NETWORK_DCE_H_
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -43,5 +42,3 @@ void modem_stop_network();
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //_NETWORK_DCE_H_
|
||||
|
@ -17,3 +17,7 @@ over PPPoS, i.e. over the modem serial line.
|
||||
* Experiment with the network, after getting the IP from the modem device
|
||||
- directly in the code
|
||||
- in the system (need to set `tun` interface IP, dns servers, and routing the desired traffic over the tun interface)
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example (using the default CMake IDF build system) is only supported from `v4.4`, since is uses `idf.py`'s linux target.
|
@ -7,39 +7,54 @@
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "esp_modem_config.h"
|
||||
#include "esp_netif.h"
|
||||
#include "vfs_resource/vfs_create.hpp"
|
||||
|
||||
|
||||
#define CONFIG_EXAMPLE_SIM_PIN "1234"
|
||||
#define CONFIG_USE_VFS_UART 1
|
||||
|
||||
using namespace esp_modem;
|
||||
|
||||
[[maybe_unused]] static const char *TAG = "linux_modem_main";
|
||||
[[maybe_unused]] constexpr auto TAG = "linux_modem_main";
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
// init the DTE
|
||||
esp_modem_dte_config_t dte_config = {
|
||||
.dte_buffer_size = 512,
|
||||
.task_stack_size = 1024,
|
||||
.task_priority = 10,
|
||||
.uart_config = { },
|
||||
.vfs_config = { }
|
||||
.dte_buffer_size = 512,
|
||||
.task_stack_size = 1024,
|
||||
.task_priority = 10,
|
||||
.vfs_config = {}
|
||||
};
|
||||
dte_config.vfs_config.dev_name = "/dev/ttyUSB0";
|
||||
dte_config.vfs_config.resource = ESP_MODEM_VFS_IS_UART; // This tells the VFS to init the UART (use termux to setup baudrate, etc.)
|
||||
#if CONFIG_USE_VFS_UART == 1
|
||||
struct esp_modem_vfs_uart_creator uart_config = {
|
||||
.dev_name = "/dev/ttyUSB0",
|
||||
.uart = {}
|
||||
};
|
||||
assert(vfs_create_uart(&uart_config, &dte_config.vfs_config) == true);
|
||||
#else
|
||||
/**
|
||||
* @note: It is possible to setup a serial to socket bridge, running a this on a remote host which connects `/dev/ttyS0` to the modem
|
||||
* socat TCP-L:2222 GOPEN:/dev/ttyS0,ispeed=115200,ospeed=1152000,b115200,raw,echo=0
|
||||
*/
|
||||
struct esp_modem_vfs_socket_creator socket_config = {
|
||||
.host_name = "raspberrypi.local",
|
||||
.port = 2222
|
||||
};
|
||||
assert(vfs_create_socket(&socket_config, &dte_config.vfs_config) == true);
|
||||
#endif
|
||||
auto dte = create_vfs_dte(&dte_config);
|
||||
|
||||
esp_netif_config_t netif_config = {
|
||||
.dev_name = "/dev/net/tun",
|
||||
.if_name = "tun0"
|
||||
.dev_name = "/dev/net/tun",
|
||||
.if_name = "tun0"
|
||||
};
|
||||
esp_netif_t *tun_netif = esp_netif_new(&netif_config);
|
||||
auto uart_dte = create_vfs_dte(&dte_config);
|
||||
|
||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG("internet");
|
||||
|
||||
auto dce = create_SIM7600_dce(&dce_config, uart_dte, tun_netif);
|
||||
auto dce = create_SIM7600_dce(&dce_config, dte, tun_netif);
|
||||
assert(dce != nullptr);
|
||||
|
||||
dce->set_command_mode();
|
||||
@ -50,16 +65,18 @@ int main()
|
||||
usleep(1000000);
|
||||
}
|
||||
std::string str;
|
||||
dce->set_mode(esp_modem::modem_mode::CMUX_MODE);
|
||||
// dce->set_mode(esp_modem::modem_mode::CMUX_MODE);
|
||||
dce->get_imsi(str);
|
||||
ESP_LOGI(TAG, "Modem IMSI number: %s",str.c_str());
|
||||
ESP_LOGI(TAG, "Modem IMSI number: %s", str.c_str());
|
||||
dce->get_imei(str);
|
||||
ESP_LOGI(TAG, "Modem IMEI number: %s",str.c_str());
|
||||
dce->get_operator_name(str);
|
||||
ESP_LOGI(TAG, "Operator name: %s",str.c_str());
|
||||
ESP_LOGI(TAG, "Modem IMEI number: %s", str.c_str());
|
||||
while (command_result::OK != dce->get_operator_name(str)) {
|
||||
printf(".\n");
|
||||
}
|
||||
ESP_LOGI(TAG, "Operator name: %s", str.c_str());
|
||||
|
||||
dce->set_mode(esp_modem::modem_mode::DATA_MODE);
|
||||
|
||||
usleep(100'000'000);
|
||||
usleep(15'000'000);
|
||||
esp_netif_destroy(tun_netif);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
# PPPoS simple client example
|
||||
# Modem console example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
@ -14,4 +14,8 @@ This example implements two very simple network commands to demonstrate and test
|
||||
To demonstrate creating custom modem devices, this example creates a DCE object using a locally defined create method,
|
||||
that sets up the DCE based on a custom module implemented in the `my_module_dce.hpp` file. The module class only overrides
|
||||
`get_module_name()` method supplying a user defined name, but keeps all other commands the same as defined in the `GenericModule`
|
||||
class.
|
||||
class.
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.2`, due to support of the console repl mode.
|
@ -12,50 +12,52 @@
|
||||
|
||||
static const char *TAG = "modem_console_helper";
|
||||
|
||||
ConsoleCommand::ConsoleCommand(const char* command, const char* help, const std::vector<CommandArgs>& args, std::function<bool(ConsoleCommand *)> f):
|
||||
func(std::move(f))
|
||||
ConsoleCommand::ConsoleCommand(const char *command, const char *help, const std::vector<CommandArgs> &args, std::function<bool(ConsoleCommand *)> f):
|
||||
func(std::move(f))
|
||||
{
|
||||
RegisterCommand(command, help, args);
|
||||
}
|
||||
|
||||
void ConsoleCommand::RegisterCommand(const char* command, const char* help, const std::vector<CommandArgs>& args)
|
||||
void ConsoleCommand::RegisterCommand(const char *command, const char *help, const std::vector<CommandArgs> &args)
|
||||
{
|
||||
assert(last_command <= MAX_REPEAT_NR);
|
||||
void * common_arg = nullptr;
|
||||
for (auto it: args) {
|
||||
switch(it.type) {
|
||||
case ARG_END:
|
||||
break;
|
||||
case STR0:
|
||||
common_arg = arg_str0(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case STR1:
|
||||
common_arg = arg_str1(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case INT0:
|
||||
common_arg = arg_int0(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case INT1:
|
||||
common_arg = arg_int1(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case LIT0:
|
||||
common_arg = arg_lit0(it.shortopts, it.longopts, it.glossary);
|
||||
break;
|
||||
arg_type common_arg = { };
|
||||
for (auto &it : args) {
|
||||
switch (it.type) {
|
||||
case ARG_END:
|
||||
break;
|
||||
case STR0:
|
||||
common_arg.str = arg_str0(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case STR1:
|
||||
common_arg.str = arg_str1(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case INT0:
|
||||
common_arg.intx = arg_int0(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case INT1:
|
||||
common_arg.intx = arg_int1(it.shortopts, it.longopts, it.datatype, it.glossary);
|
||||
break;
|
||||
case LIT0:
|
||||
common_arg.lit = arg_lit0(it.shortopts, it.longopts, it.glossary);
|
||||
break;
|
||||
}
|
||||
if (common_arg) {
|
||||
if (common_arg.is_null()) {
|
||||
arg_table.emplace_back(common_arg);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Creating argument parser failed for %s", it.glossary);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
arg_table.emplace_back( arg_end(1));
|
||||
|
||||
arg_type end = { .end = arg_end(1) };
|
||||
arg_table.emplace_back(end);
|
||||
const esp_console_cmd_t command_def = {
|
||||
.command = command,
|
||||
.help = help,
|
||||
.hint = nullptr,
|
||||
.func = command_func_pts[last_command],
|
||||
.argtable = &arg_table[0]
|
||||
.command = command,
|
||||
.help = help,
|
||||
.hint = nullptr,
|
||||
.func = command_func_pts[last_command],
|
||||
.argtable = &arg_table[0]
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&command_def));
|
||||
last_command++;
|
||||
@ -64,13 +66,13 @@ void ConsoleCommand::RegisterCommand(const char* command, const char* help, cons
|
||||
|
||||
int ConsoleCommand::get_count(int index)
|
||||
{
|
||||
return ((struct arg_str *)arg_table[index])->count;
|
||||
return (arg_table[index].str)->count;
|
||||
}
|
||||
|
||||
std::string ConsoleCommand::get_string(int index)
|
||||
{
|
||||
if (get_count(index) > 0) {
|
||||
return std::string(((struct arg_str *)arg_table[index])->sval[0]);
|
||||
return std::string(arg_table[index].str->sval[0]);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
@ -78,17 +80,18 @@ std::string ConsoleCommand::get_string(int index)
|
||||
int ConsoleCommand::get_int(int index)
|
||||
{
|
||||
if (get_count(index) > 0) {
|
||||
return *((struct arg_int *)arg_table[index])->ival;
|
||||
return *(arg_table[index].intx)->ival;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int ConsoleCommand::command_func(int argc, char **argv) {
|
||||
void * plain_arg_array = &arg_table[0];
|
||||
int ConsoleCommand::command_func(int argc, char **argv)
|
||||
{
|
||||
arg_type *plain_arg_array = &arg_table[0];
|
||||
int nerrors = arg_parse(argc, argv, (void **)plain_arg_array);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, (struct arg_end *) arg_table.back(), argv[0]);
|
||||
arg_print_errors(stderr, arg_table.back().end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if (func) {
|
||||
@ -120,7 +123,7 @@ const esp_console_cmd_func_t ConsoleCommand::command_func_pts[] = {
|
||||
|
||||
#define ITEM_TO_REPEAT(index) StaticCommands::command_func_ ## index ,
|
||||
|
||||
_DO_REPEAT_ITEM()
|
||||
_DO_REPEAT_ITEM()
|
||||
|
||||
#undef ITEM_TO_REPEAT
|
||||
};
|
||||
@ -128,5 +131,5 @@ const esp_console_cmd_func_t ConsoleCommand::command_func_pts[] = {
|
||||
/**
|
||||
* @brief Static members defined for ConsoleCommand
|
||||
*/
|
||||
std::vector<ConsoleCommand*> ConsoleCommand::console_commands;
|
||||
std::vector<ConsoleCommand *> ConsoleCommand::console_commands;
|
||||
int ConsoleCommand::last_command = 0;
|
||||
|
@ -7,8 +7,7 @@
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef MODEM_CONSOLE_CONSOLE_HELPER_H
|
||||
#define MODEM_CONSOLE_CONSOLE_HELPER_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
@ -35,10 +34,10 @@ enum arg_type {
|
||||
* Command argument struct definition for list of arguments of one command
|
||||
*/
|
||||
struct CommandArgs {
|
||||
CommandArgs(arg_type t, const char * shopts, const char * lopts, const char * data, const char * glos):
|
||||
CommandArgs(arg_type t, const char *shopts, const char *lopts, const char *data, const char *glos):
|
||||
type(t), shortopts(shopts), longopts(lopts), datatype(data), glossary(glos) {}
|
||||
CommandArgs(arg_type t, const char * shopts, const char * lopts, const char * glos):
|
||||
type(t), shortopts(shopts), longopts(lopts), datatype(nullptr), glossary(glos) {}
|
||||
CommandArgs(arg_type t, const char *shopts, const char *lopts, const char *glos):
|
||||
type(t), shortopts(shopts), longopts(lopts), datatype(nullptr), glossary(glos) {}
|
||||
|
||||
arg_type type;
|
||||
const char *shortopts;
|
||||
@ -53,6 +52,21 @@ class StaticCommands;
|
||||
* @brief This class simplifies console command definition in more object wise fashion
|
||||
*/
|
||||
class ConsoleCommand {
|
||||
/**
|
||||
* @brief Common argument types to be stored internally for parsing later
|
||||
*/
|
||||
using arg_type =
|
||||
union {
|
||||
struct arg_int *intx;
|
||||
struct arg_str *str;
|
||||
struct arg_lit *lit;
|
||||
struct arg_end *end;
|
||||
void *__raw_ptr;
|
||||
bool is_null() const {
|
||||
return __raw_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
friend class StaticCommands;
|
||||
public:
|
||||
/**
|
||||
@ -63,8 +77,8 @@ public:
|
||||
* @param srg_struct_size Size of the argument struct
|
||||
* @param f Function callback for the command
|
||||
*/
|
||||
template<typename T> explicit ConsoleCommand(const char* command, const char* help, const T *arg_struct, size_t srg_struct_size,
|
||||
std::function<bool(ConsoleCommand *)> f): func(std::move(f))
|
||||
template<typename T> explicit ConsoleCommand(const char *command, const char *help, const T *arg_struct, size_t srg_struct_size,
|
||||
std::function<bool(ConsoleCommand *)> f): func(std::move(f))
|
||||
{
|
||||
size_t args_plain_size = srg_struct_size / sizeof(CommandArgs);
|
||||
auto first_arg = reinterpret_cast<const CommandArgs *>(arg_struct);
|
||||
@ -75,29 +89,38 @@ public:
|
||||
/**
|
||||
* @brief Another method of Console command definitions using vector arg struct
|
||||
*/
|
||||
explicit ConsoleCommand(const char* command, const char* help, const std::vector<CommandArgs>& args, std::function<bool(ConsoleCommand *)> f);
|
||||
explicit ConsoleCommand(const char *command, const char *help, const std::vector<CommandArgs> &args, std::function<bool(ConsoleCommand *)> f);
|
||||
|
||||
/**
|
||||
* @brief Utility getters of various params from the argument list
|
||||
*/
|
||||
template<typename T> int get_count_of(CommandArgs T::*member) { return get_count(index_arg(member)); }
|
||||
template<typename T> std::string get_string_of(CommandArgs T::*member) { return get_string(index_arg(member)); }
|
||||
template<typename T> int get_int_of(CommandArgs T::*member) { return get_int(index_arg(member)); }
|
||||
template<typename T> int get_count_of(CommandArgs T::*member)
|
||||
{
|
||||
return get_count(index_arg(member));
|
||||
}
|
||||
template<typename T> std::string get_string_of(CommandArgs T::*member)
|
||||
{
|
||||
return get_string(index_arg(member));
|
||||
}
|
||||
template<typename T> int get_int_of(CommandArgs T::*member)
|
||||
{
|
||||
return get_int(index_arg(member));
|
||||
}
|
||||
std::string get_string(int index);
|
||||
int get_int(int index);
|
||||
|
||||
private:
|
||||
int get_count(int index);
|
||||
void RegisterCommand(const char* command, const char* help, const std::vector<CommandArgs>& args);
|
||||
void RegisterCommand(const char *command, const char *help, const std::vector<CommandArgs> &args);
|
||||
template<typename T> static constexpr size_t index_arg(CommandArgs T::*member)
|
||||
{ return ((uint8_t *)&((T*)nullptr->*member) - (uint8_t *)nullptr)/sizeof(CommandArgs); }
|
||||
std::vector<void*> arg_table;
|
||||
{
|
||||
return ((uint8_t *) & ((T *)nullptr->*member) - (uint8_t *)nullptr) / sizeof(CommandArgs);
|
||||
}
|
||||
std::vector<arg_type> arg_table;
|
||||
int command_func(int argc, char **argv);
|
||||
|
||||
static int last_command;
|
||||
static std::vector<ConsoleCommand*> console_commands;
|
||||
static std::vector<ConsoleCommand *> console_commands;
|
||||
std::function<bool(ConsoleCommand *)> func;
|
||||
const static esp_console_cmd_func_t command_func_pts[];
|
||||
};
|
||||
|
||||
#endif //MODEM_CONSOLE_CONSOLE_HELPER_H
|
||||
|
@ -46,6 +46,7 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -83,9 +84,9 @@ static int do_http_client(int argc, char **argv)
|
||||
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
|
||||
esp_http_client_get_status_code(client),
|
||||
esp_http_client_get_content_length(client));
|
||||
uint64_t content_length = esp_http_client_get_content_length(client);
|
||||
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %lld",
|
||||
esp_http_client_get_status_code(client), content_length);
|
||||
return 0;
|
||||
}
|
||||
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
|
||||
@ -105,4 +106,4 @@ void modem_console_register_http(void)
|
||||
.argtable = &http_args
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&http_cmd));
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ extern "C" void app_main(void)
|
||||
SetModeArgs(): mode(STR1, nullptr, nullptr, "<mode>", "PPP, CMD or CMUX") {}
|
||||
CommandArgs mode;
|
||||
} set_mode_args;
|
||||
const ConsoleCommand SetModeParser("set_mode", "sets modem mode", &set_mode_args, sizeof(set_mode_args), [&](ConsoleCommand *c){
|
||||
const ConsoleCommand SetModeParser("set_mode", "sets modem mode", &set_mode_args, sizeof(set_mode_args), [&](ConsoleCommand * c) {
|
||||
if (c->get_count_of(&SetModeArgs::mode)) {
|
||||
auto mode = c->get_string_of(&SetModeArgs::mode);
|
||||
modem_mode dev_mode;
|
||||
@ -101,7 +101,7 @@ extern "C" void app_main(void)
|
||||
SetPinArgs(): pin(STR1, nullptr, nullptr, "<pin>", "PIN") {}
|
||||
CommandArgs pin;
|
||||
} set_pin_args;
|
||||
const ConsoleCommand SetPinParser("set_pin", "sets SIM card PIN", &set_pin_args, sizeof(set_pin_args), [&](ConsoleCommand *c){
|
||||
const ConsoleCommand SetPinParser("set_pin", "sets SIM card PIN", &set_pin_args, sizeof(set_pin_args), [&](ConsoleCommand * c) {
|
||||
if (c->get_count_of(&SetPinArgs::pin)) {
|
||||
auto pin = c->get_string_of(&SetPinArgs::pin);
|
||||
ESP_LOGI(TAG, "Setting pin=%s...", pin.c_str());
|
||||
@ -109,7 +109,7 @@ extern "C" void app_main(void)
|
||||
if (err == command_result::OK) {
|
||||
ESP_LOGI(TAG, "OK");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed %s", err == command_result::TIMEOUT ? "TIMEOUT":"");
|
||||
ESP_LOGE(TAG, "Failed %s", err == command_result::TIMEOUT ? "TIMEOUT" : "");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -117,26 +117,26 @@ extern "C" void app_main(void)
|
||||
});
|
||||
|
||||
const std::vector<CommandArgs> no_args;
|
||||
const ConsoleCommand ReadPinArgs("read_pin", "checks if SIM is unlocked", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand ReadPinArgs("read_pin", "checks if SIM is unlocked", no_args, [&](ConsoleCommand * c) {
|
||||
bool pin_ok;
|
||||
ESP_LOGI(TAG, "Checking pin...");
|
||||
auto err = dce->read_pin(pin_ok);
|
||||
if (err == command_result::OK) {
|
||||
ESP_LOGI(TAG, "OK. Pin status: %s", pin_ok ? "true": "false");
|
||||
ESP_LOGI(TAG, "OK. Pin status: %s", pin_ok ? "true" : "false");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed %s", err == command_result::TIMEOUT ? "TIMEOUT":"");
|
||||
ESP_LOGE(TAG, "Failed %s", err == command_result::TIMEOUT ? "TIMEOUT" : "");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const ConsoleCommand GetModuleName("get_module_name", "reads the module name", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand GetModuleName("get_module_name", "reads the module name", no_args, [&](ConsoleCommand * c) {
|
||||
std::string module_name;
|
||||
ESP_LOGI(TAG, "Reading module name...");
|
||||
CHECK_ERR(dce->get_module_name(module_name), ESP_LOGI(TAG, "OK. Module name: %s", module_name.c_str()));
|
||||
});
|
||||
|
||||
const ConsoleCommand GetOperatorName("get_operator_name", "reads the operator name", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand GetOperatorName("get_operator_name", "reads the operator name", no_args, [&](ConsoleCommand * c) {
|
||||
std::string operator_name;
|
||||
ESP_LOGI(TAG, "Reading operator name...");
|
||||
CHECK_ERR(dce->get_operator_name(operator_name), ESP_LOGI(TAG, "OK. Operator name: %s", operator_name.c_str()));
|
||||
@ -153,39 +153,41 @@ extern "C" void app_main(void)
|
||||
CommandArgs pattern;
|
||||
CommandArgs no_cr;
|
||||
} send_cmd_args;
|
||||
const ConsoleCommand SendCommand("cmd", "sends generic AT command, no_args", &send_cmd_args, sizeof(send_cmd_args), [&](ConsoleCommand *c) {
|
||||
const ConsoleCommand SendCommand("cmd", "sends generic AT command, no_args", &send_cmd_args, sizeof(send_cmd_args), [&](ConsoleCommand * c) {
|
||||
auto cmd = c->get_string_of(&GenericCommandArgs::cmd);
|
||||
auto timeout = c->get_count_of(&GenericCommandArgs::timeout) ? c->get_int_of(&GenericCommandArgs::timeout)
|
||||
: 1000;
|
||||
: 1000;
|
||||
ESP_LOGI(TAG, "Sending command %s with timeout %d", cmd.c_str(), timeout);
|
||||
auto pattern = c->get_string_of(&GenericCommandArgs::pattern);
|
||||
if (c->get_count_of(&GenericCommandArgs::no_cr) == 0) {
|
||||
cmd += '\r';
|
||||
}
|
||||
ESP_LOGI(TAG, "Sending command %s with timeout %d", cmd.c_str(), timeout);
|
||||
CHECK_ERR(dce->command(cmd, [&](uint8_t *data, size_t len) {
|
||||
std::string response((char *) data, len);
|
||||
ESP_LOGI(TAG, "%s", response.c_str());
|
||||
if (pattern.empty() || response.find(pattern) != std::string::npos)
|
||||
if (pattern.empty() || response.find(pattern) != std::string::npos) {
|
||||
return command_result::OK;
|
||||
if (response.find(pattern) != std::string::npos)
|
||||
}
|
||||
if (response.find(pattern) != std::string::npos) {
|
||||
return command_result::OK;
|
||||
}
|
||||
return command_result::TIMEOUT;
|
||||
}, timeout),);
|
||||
});
|
||||
|
||||
const ConsoleCommand GetSignalQuality("get_signal_quality", "Gets signal quality", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand GetSignalQuality("get_signal_quality", "Gets signal quality", no_args, [&](ConsoleCommand * c) {
|
||||
int rssi, ber;
|
||||
CHECK_ERR(dce->get_signal_quality(rssi, ber), ESP_LOGI(TAG, "OK. rssi=%d, ber=%d", rssi, ber));
|
||||
});
|
||||
const ConsoleCommand GetBatteryStatus("get_battery_status", "Reads voltage/battery status", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand GetBatteryStatus("get_battery_status", "Reads voltage/battery status", no_args, [&](ConsoleCommand * c) {
|
||||
int volt, bcl, bcs;
|
||||
CHECK_ERR(dce->get_battery_status(volt, bcl, bcs), ESP_LOGI(TAG, "OK. volt=%d, bcl=%d, bcs=%d", volt, bcl, bcs));
|
||||
});
|
||||
const ConsoleCommand PowerDown("power_down", "power down the module", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand PowerDown("power_down", "power down the module", no_args, [&](ConsoleCommand * c) {
|
||||
ESP_LOGI(TAG, "Power down the module...");
|
||||
CHECK_ERR(dce->power_down(), ESP_LOGI(TAG, "OK"));
|
||||
});
|
||||
const ConsoleCommand Reset("reset", "reset the module", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand Reset("reset", "reset the module", no_args, [&](ConsoleCommand * c) {
|
||||
ESP_LOGI(TAG, "Resetting the module...");
|
||||
CHECK_ERR(dce->reset(), ESP_LOGI(TAG, "OK"));
|
||||
});
|
||||
@ -193,7 +195,7 @@ extern "C" void app_main(void)
|
||||
SetApn(): apn(STR1, nullptr, nullptr, "<apn>", "APN (Access Point Name)") {}
|
||||
CommandArgs apn;
|
||||
} set_apn;
|
||||
const ConsoleCommand SetApnParser("set_apn", "sets APN", &set_apn, sizeof(set_apn), [&](ConsoleCommand *c){
|
||||
const ConsoleCommand SetApnParser("set_apn", "sets APN", &set_apn, sizeof(set_apn), [&](ConsoleCommand * c) {
|
||||
if (c->get_count_of(&SetApn::apn)) {
|
||||
auto apn = c->get_string_of(&SetApn::apn);
|
||||
ESP_LOGI(TAG, "Setting the APN=%s...", apn.c_str());
|
||||
@ -205,7 +207,7 @@ extern "C" void app_main(void)
|
||||
});
|
||||
|
||||
SignalGroup exit_signal;
|
||||
const ConsoleCommand ExitConsole("exit", "exit the console application", no_args, [&](ConsoleCommand *c){
|
||||
const ConsoleCommand ExitConsole("exit", "exit the console application", no_args, [&](ConsoleCommand * c) {
|
||||
ESP_LOGI(TAG, "Exiting...");
|
||||
exit_signal.set(1);
|
||||
s_repl->del(s_repl);
|
||||
|
@ -7,8 +7,7 @@
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef __MY_MODULE_DCE_HPP__
|
||||
#define __MY_MODULE_DCE_HPP__
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "cxx_include/esp_modem_dce_factory.hpp"
|
||||
@ -21,7 +20,7 @@
|
||||
class MyShinyModem: public esp_modem::GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
esp_modem::command_result get_module_name(std::string& name) override
|
||||
esp_modem::command_result get_module_name(std::string &name) override
|
||||
{
|
||||
name = "Custom Shiny Module";
|
||||
return esp_modem::command_result::OK;
|
||||
@ -33,11 +32,8 @@ public:
|
||||
* @return unique pointer of the resultant DCE
|
||||
*/
|
||||
std::unique_ptr<esp_modem::DCE> create_shiny_dce(const esp_modem::dce_config *config,
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif)
|
||||
std::shared_ptr<esp_modem::DTE> dte,
|
||||
esp_netif_t *netif)
|
||||
{
|
||||
return esp_modem::dce_factory::Factory::build_unique<MyShinyModem>(config, std::move(dte), netif);
|
||||
}
|
||||
|
||||
|
||||
#endif //__MY_MODULE_DCE_HPP__
|
@ -8,3 +8,7 @@ This example shows how to act as a MQTT client after the PPPoS channel created b
|
||||
## How to use this example
|
||||
|
||||
See the README.md file in the upper level `pppos` directory for more information about the PPPoS examples.
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.1`, as this is the default dependency of `esp-modem` component.
|
@ -15,3 +15,7 @@ The example uses the following configuration options to demonstrate basic esp-mo
|
||||
## About the esp_modem
|
||||
|
||||
Please check the component [README](../../README.md)
|
||||
|
||||
### Supported IDF versions
|
||||
|
||||
This example is only supported from `v4.3`, since is uses an experimental `esp_event_cxx` component.
|
@ -19,7 +19,7 @@
|
||||
#include "simple_mqtt_client.hpp"
|
||||
#include "esp_vfs_dev.h" // For optional VFS support
|
||||
#include "esp_https_ota.h" // For potential OTA configuration
|
||||
|
||||
#include "vfs_resource/vfs_create.hpp"
|
||||
|
||||
#define BROKER_URL "mqtt://mqtt.eclipseprojects.io"
|
||||
|
||||
@ -46,11 +46,11 @@ extern "C" void app_main(void)
|
||||
* so doesn't give any practical benefit besides the FD use demonstration and a placeholder
|
||||
* to use FD terminal for other devices
|
||||
*/
|
||||
dte_config.vfs_config.dev_name = "/dev/uart/1";
|
||||
dte_config.vfs_config.resource = ESP_MODEM_VFS_IS_UART;
|
||||
dte_config.uart_config.event_queue_size = 0;
|
||||
struct esp_modem_vfs_uart_creator uart_config = ESP_MODEM_VFS_DEFAULT_UART_CONFIG("/dev/uart/1");
|
||||
assert(vfs_create_uart(&uart_config, &dte_config.vfs_config) == true);
|
||||
|
||||
auto dte = create_vfs_dte(&dte_config);
|
||||
esp_vfs_dev_uart_use_driver(dte_config.uart_config.port_num);
|
||||
esp_vfs_dev_uart_use_driver(uart_config.uart.port_num);
|
||||
#else
|
||||
auto dte = create_uart_dte(&dte_config);
|
||||
#endif // CONFIG_EXAMPLE_USE_VFS_TERM
|
||||
@ -122,10 +122,10 @@ extern "C" void app_main(void)
|
||||
event_handler.listen_to(MqttClient::get_event(MqttClient::Event::DATA));
|
||||
|
||||
auto reg = loop->register_event(MqttClient::get_event(MqttClient::Event::DATA),
|
||||
[&mqtt](const ESPEvent &event, void *data) {
|
||||
std::cout << " TOPIC:" << mqtt.get_topic(data) << std::endl;
|
||||
std::cout << " DATA:" << mqtt.get_data(data) << std::endl;
|
||||
});
|
||||
[&mqtt](const ESPEvent & event, void *data) {
|
||||
std::cout << " TOPIC:" << mqtt.get_topic(data) << std::endl;
|
||||
std::cout << " DATA:" << mqtt.get_data(data) << std::endl;
|
||||
});
|
||||
mqtt.connect();
|
||||
while (true) {
|
||||
result = event_handler.wait_event_for(std::chrono::milliseconds(60000));
|
||||
|
@ -22,9 +22,8 @@ ESP_EVENT_DECLARE_BASE(MQTT_EVENTS);
|
||||
/**
|
||||
* Thin wrapper around C mqtt_client
|
||||
*/
|
||||
struct MqttClientHandle
|
||||
{
|
||||
explicit MqttClientHandle(const std::string & uri)
|
||||
struct MqttClientHandle {
|
||||
explicit MqttClientHandle(const std::string &uri)
|
||||
{
|
||||
esp_mqtt_client_config_t config = { };
|
||||
config.uri = uri.c_str();
|
||||
@ -49,9 +48,9 @@ struct MqttClientHandle
|
||||
/**
|
||||
* @brief Definitions of MqttClient methods
|
||||
*/
|
||||
MqttClient::MqttClient(const std::string & uri):
|
||||
MqttClient::MqttClient(const std::string &uri):
|
||||
h(std::unique_ptr<MqttClientHandle>(new MqttClientHandle(uri)))
|
||||
{}
|
||||
{}
|
||||
|
||||
void MqttClient::connect()
|
||||
{
|
||||
@ -61,11 +60,11 @@ void MqttClient::connect()
|
||||
idf::event::ESPEvent MqttClient::get_event(MqttClient::Event ev)
|
||||
{
|
||||
switch (ev) {
|
||||
case Event::CONNECT: {
|
||||
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_CONNECTED) };
|
||||
}
|
||||
case Event::DATA:
|
||||
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_DATA) };
|
||||
case Event::CONNECT: {
|
||||
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_CONNECTED) };
|
||||
}
|
||||
case Event::DATA:
|
||||
return { MQTT_EVENTS, ESPEventID(MQTT_EVENT_DATA) };
|
||||
}
|
||||
return { };
|
||||
}
|
||||
@ -80,7 +79,7 @@ int MqttClient::subscribe(const std::string &topic, int qos)
|
||||
return esp_mqtt_client_subscribe(h->client, topic.c_str(), qos);
|
||||
}
|
||||
|
||||
std::string MqttClient::get_topic(void * event_data)
|
||||
std::string MqttClient::get_topic(void *event_data)
|
||||
{
|
||||
auto event = (esp_mqtt_event_handle_t)event_data;
|
||||
if (event == nullptr || event->client != h->client)
|
||||
@ -89,7 +88,7 @@ std::string MqttClient::get_topic(void * event_data)
|
||||
return std::string(event->topic, event->topic_len);
|
||||
}
|
||||
|
||||
std::string MqttClient::get_data(void * event_data)
|
||||
std::string MqttClient::get_data(void *event_data)
|
||||
{
|
||||
auto event = (esp_mqtt_event_handle_t)event_data;
|
||||
if (event == nullptr || event->client != h->client)
|
||||
|
@ -6,8 +6,7 @@
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#ifndef _SIMPLE_MQTT_CLIENT_H_
|
||||
#define _SIMPLE_MQTT_CLIENT_H_
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
@ -25,7 +24,7 @@ public:
|
||||
DATA,
|
||||
};
|
||||
|
||||
explicit MqttClient(const std::string & uri);
|
||||
explicit MqttClient(const std::string &uri);
|
||||
~MqttClient();
|
||||
|
||||
/**
|
||||
@ -40,7 +39,7 @@ public:
|
||||
* @param qos QoS (0 by default)
|
||||
* @return message id
|
||||
*/
|
||||
int publish(const std::string & topic, const std::string & data, int qos = 0);
|
||||
int publish(const std::string &topic, const std::string &data, int qos = 0);
|
||||
|
||||
/**
|
||||
* @brief Subscribe to a topic
|
||||
@ -48,7 +47,7 @@ public:
|
||||
* @param qos QoS (0 by default)
|
||||
* @return message id
|
||||
*/
|
||||
int subscribe(const std::string & topic, int qos = 0);
|
||||
int subscribe(const std::string &topic, int qos = 0);
|
||||
|
||||
/**
|
||||
* @brief Get topic from event data
|
||||
@ -72,6 +71,3 @@ public:
|
||||
private:
|
||||
std::unique_ptr<MqttClientHandle> h;
|
||||
};
|
||||
|
||||
|
||||
#endif //_SIMPLE_MQTT_CLIENT_H_
|
||||
|
@ -6,5 +6,7 @@ CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
|
||||
CONFIG_LWIP_PPP_ENABLE_IPV6=n
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_PARTITION_TABLE_TWO_OTA=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF=y
|
||||
CONFIG_NEWLIB_STDIN_LINE_ENDING_LF=y
|
||||
CONFIG_NEWLIB_STDIN_LINE_ENDING_LF=y
|
||||
CONFIG_MAIN_TASK_STACK_SIZE=8192
|
@ -1,4 +1,4 @@
|
||||
version: "0.1.6"
|
||||
version: "0.1.13"
|
||||
description: esp modem
|
||||
dependencies:
|
||||
# Required IDF version
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_API_HPP_
|
||||
#define _ESP_MODEM_API_HPP_
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "cxx_include/esp_modem_dce.hpp"
|
||||
@ -74,7 +73,7 @@ std::shared_ptr<DTE> create_vfs_dte(const dte_config *config);
|
||||
/**
|
||||
* @brief Create DCE based on SIM7600 module
|
||||
* @param config DCE configuration
|
||||
* @param DTE reference to the communicating DTE
|
||||
* @param dte reference to the communicating DTE
|
||||
* @param netif reference to the network interface
|
||||
*
|
||||
* @return unique ptr to the created DCE on success
|
||||
@ -103,5 +102,3 @@ std::unique_ptr<DCE> create_generic_dce(const dce_config *config, std::shared_pt
|
||||
*/
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_API_HPP_
|
@ -12,14 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_CMUX_HPP_
|
||||
#define _ESP_MODEM_CMUX_HPP_
|
||||
#pragma once
|
||||
|
||||
#include "esp_modem_terminal.hpp"
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
constexpr size_t max_terms = 2;
|
||||
constexpr size_t MAX_TERMINALS_NUM = 2;
|
||||
/**
|
||||
* @defgroup ESP_MODEM_CMUX ESP_MODEM CMUX class
|
||||
* @brief Definition of CMUX terminal
|
||||
@ -51,38 +50,79 @@ class CMuxInstance;
|
||||
|
||||
/**
|
||||
* @brief CMux class which consumes the original terminal and creates multiple virtual terminals from it.
|
||||
* This class is not usable applicable as a DTE terminal
|
||||
* This class itself is not usable as a DTE terminal, only via its instances defined in `CMuxInstance`
|
||||
*/
|
||||
class CMux {
|
||||
public:
|
||||
explicit CMux(std::unique_ptr<Terminal> t, std::unique_ptr<uint8_t[]> b, size_t buff_size):
|
||||
term(std::move(t)), buffer_size(buff_size), buffer(std::move(b)), payload_start(nullptr), total_payload_size(0) {}
|
||||
term(std::move(t)), payload_start(nullptr), total_payload_size(0), buffer_size(buff_size), buffer(std::move(b)) {}
|
||||
~CMux() = default;
|
||||
|
||||
/**
|
||||
* @brief Initializes CMux protocol
|
||||
* @return true on success
|
||||
*/
|
||||
[[nodiscard]] bool init();
|
||||
|
||||
/**
|
||||
* @brief Sets read callback for the appropriate terminal
|
||||
* @param inst Index of the terminal
|
||||
* @param f function pointer
|
||||
*/
|
||||
void set_read_cb(int inst, std::function<bool(uint8_t *data, size_t len)> f);
|
||||
|
||||
/**
|
||||
* @brief Writes to the appropriate terminal
|
||||
* @param i Index of the terminal
|
||||
* @param data Data to write
|
||||
* @param len Data length to write
|
||||
* @return The actual written length
|
||||
*/
|
||||
int write(int i, uint8_t *data, size_t len);
|
||||
|
||||
private:
|
||||
std::function<bool(uint8_t *data, size_t len)> read_cb[max_terms];
|
||||
void data_available(uint8_t *data, size_t len);
|
||||
void send_sabm(size_t i);
|
||||
std::unique_ptr<Terminal> term;
|
||||
cmux_state state;
|
||||
static uint8_t fcs_crc(const uint8_t frame[6]); /*!< Utility to calculate FCS CRC */
|
||||
void data_available(uint8_t *data, size_t len); /*!< Called when valid data available */
|
||||
void send_sabm(size_t i); /*!< Sending initial SABM */
|
||||
bool on_cmux(uint8_t *data, size_t len); /*!< Called from terminal layer when raw CMUX protocol data available */
|
||||
|
||||
struct CMuxFrame; /*!< Forward declare the Frame struct, used in protocol decoders */
|
||||
/**
|
||||
* These methods serve different states of the CMUX protocols
|
||||
* @param frame Currently available cmux frame (basically data, size, methods)
|
||||
* @return - true if the state processed successfully
|
||||
* - false if more data needed to process the current state
|
||||
*/
|
||||
bool on_recovery(CMuxFrame &frame);
|
||||
bool on_init(CMuxFrame &frame);
|
||||
bool on_header(CMuxFrame &frame);
|
||||
bool on_payload(CMuxFrame &frame);
|
||||
bool on_footer(CMuxFrame &frame);
|
||||
|
||||
std::function<bool(uint8_t *data, size_t len)> read_cb[MAX_TERMINALS_NUM]; /*!< Function pointers to read callbacks */
|
||||
std::unique_ptr<Terminal> term; /*!< The original terminal */
|
||||
cmux_state state; /*!< CMux protocol state */
|
||||
|
||||
/**
|
||||
* CMux control fields and offsets
|
||||
*/
|
||||
uint8_t dlci;
|
||||
uint8_t type;
|
||||
size_t payload_len;
|
||||
uint8_t frame_header[6];
|
||||
size_t frame_header_offset;
|
||||
size_t buffer_size;
|
||||
std::unique_ptr<uint8_t[]> buffer;
|
||||
bool on_cmux(uint8_t *data, size_t len);
|
||||
static uint8_t fcs_crc(const uint8_t frame[6]);
|
||||
Lock lock;
|
||||
int instance;
|
||||
int sabm_ack;
|
||||
uint8_t *payload_start;
|
||||
size_t total_payload_size;
|
||||
int instance;
|
||||
int sabm_ack;
|
||||
|
||||
/**
|
||||
* Processing buffer size and pointer
|
||||
*/
|
||||
size_t buffer_size;
|
||||
std::unique_ptr<uint8_t[]> buffer;
|
||||
|
||||
Lock lock;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -93,14 +133,23 @@ class CMuxInstance: public Terminal {
|
||||
public:
|
||||
explicit CMuxInstance(std::shared_ptr<CMux> parent, int i): cmux(std::move(parent)), instance(i) {}
|
||||
|
||||
int write(uint8_t *data, size_t len) override { return cmux->write(instance, data, len); }
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override { return cmux->set_read_cb(instance, std::move(f)); }
|
||||
int read(uint8_t *data, size_t len) override { return 0; }
|
||||
int write(uint8_t *data, size_t len) override
|
||||
{
|
||||
return cmux->write(instance, data, len);
|
||||
}
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override
|
||||
{
|
||||
return cmux->set_read_cb(instance, std::move(f));
|
||||
}
|
||||
int read(uint8_t *data, size_t len) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void start() override { }
|
||||
void stop() override { }
|
||||
private:
|
||||
std::shared_ptr<CMux> cmux;
|
||||
int instance;
|
||||
size_t instance;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -108,5 +157,3 @@ private:
|
||||
*/
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_CMUX_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_COMMAND_LIBRARY_HPP_
|
||||
#define _ESP_MODEM_COMMAND_LIBRARY_HPP_
|
||||
#pragma once
|
||||
|
||||
#include "esp_modem_dte.hpp"
|
||||
#include "esp_modem_dce_module.hpp"
|
||||
@ -37,17 +36,17 @@ namespace dce_commands {
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, num, ...) \
|
||||
return_type name(CommandableIf *t, ## __VA_ARGS__);
|
||||
|
||||
DECLARE_ALL_COMMAND_APIS(declare name(Commandable *p, ...);)
|
||||
DECLARE_ALL_COMMAND_APIS(declare name(Commandable *p, ...);)
|
||||
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
/**
|
||||
* @brief Following commands that are different for some specific modules
|
||||
*/
|
||||
command_result get_battery_status_sim7xxx(CommandableIf* t, int& voltage, int &bcs, int &bcl);
|
||||
command_result power_down_sim7xxx(CommandableIf* t);
|
||||
command_result power_down_sim8xx(CommandableIf* t);
|
||||
command_result set_data_mode_sim8xx(CommandableIf* t);
|
||||
command_result get_battery_status_sim7xxx(CommandableIf *t, int &voltage, int &bcs, int &bcl);
|
||||
command_result power_down_sim7xxx(CommandableIf *t);
|
||||
command_result power_down_sim8xx(CommandableIf *t);
|
||||
command_result set_data_mode_sim8xx(CommandableIf *t);
|
||||
|
||||
/**
|
||||
* @}
|
||||
@ -55,5 +54,3 @@ command_result set_data_mode_sim8xx(CommandableIf* t);
|
||||
|
||||
} // dce_commands
|
||||
} // esp_modem
|
||||
|
||||
#endif //_ESP_MODEM_COMMAND_LIBRARY_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_DCE_HPP_
|
||||
#define _ESP_MODEM_DCE_HPP_
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "cxx_include/esp_modem_netif.hpp"
|
||||
@ -53,8 +52,8 @@ template<class SpecificModule>
|
||||
class DCE_T {
|
||||
static_assert(std::is_base_of<ModuleIf, SpecificModule>::value, "DCE must be instantiated with Module class only");
|
||||
public:
|
||||
explicit DCE_T(const std::shared_ptr<DTE>& dte, std::shared_ptr<SpecificModule> dev, esp_netif_t * netif):
|
||||
dte(dte), device(std::move(dev)), netif(dte, netif)
|
||||
explicit DCE_T(const std::shared_ptr<DTE> &dte, std::shared_ptr<SpecificModule> dev, esp_netif_t *netif):
|
||||
dte(dte), device(std::move(dev)), netif(dte, netif)
|
||||
{ }
|
||||
|
||||
~DCE_T() = default;
|
||||
@ -62,20 +61,35 @@ public:
|
||||
/**
|
||||
* @brief Set data mode!
|
||||
*/
|
||||
void set_data() { set_mode(modem_mode::DATA_MODE); }
|
||||
void set_data()
|
||||
{
|
||||
set_mode(modem_mode::DATA_MODE);
|
||||
}
|
||||
|
||||
void exit_data() { set_mode(modem_mode::COMMAND_MODE); }
|
||||
void exit_data()
|
||||
{
|
||||
set_mode(modem_mode::COMMAND_MODE);
|
||||
}
|
||||
|
||||
void set_cmux() { set_mode(modem_mode::CMUX_MODE); }
|
||||
void set_cmux()
|
||||
{
|
||||
set_mode(modem_mode::CMUX_MODE);
|
||||
}
|
||||
|
||||
SpecificModule* get_module() { return device.get(); }
|
||||
SpecificModule *get_module()
|
||||
{
|
||||
return device.get();
|
||||
}
|
||||
|
||||
command_result command(const std::string& command, got_line_cb got_line, uint32_t time_ms)
|
||||
command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms)
|
||||
{
|
||||
return dte->command(command, std::move(got_line), time_ms);
|
||||
}
|
||||
|
||||
bool set_mode(modem_mode m) { return mode.set(dte.get(), device.get(), netif, m); }
|
||||
bool set_mode(modem_mode m)
|
||||
{
|
||||
return mode.set(dte.get(), device.get(), netif, m);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<DTE> dte;
|
||||
@ -86,9 +100,9 @@ protected:
|
||||
|
||||
/**
|
||||
* @brief Common abstraction of the modem DCE, specialized by the GenericModule which is a parent class for the supported
|
||||
* defices and most common modems, as well.
|
||||
* devices and most common modems, as well.
|
||||
*/
|
||||
class DCE: public DCE_T<GenericModule> {
|
||||
class DCE : public DCE_T<GenericModule> {
|
||||
public:
|
||||
|
||||
using DCE_T<GenericModule>::DCE_T;
|
||||
@ -99,7 +113,10 @@ public:
|
||||
return device->name(std::forward<Agrs>(args)...); \
|
||||
}
|
||||
|
||||
DECLARE_ALL_COMMAND_APIS(forwards name(...) { device->name(...); } )
|
||||
DECLARE_ALL_COMMAND_APIS(forwards name(...)
|
||||
{
|
||||
device->name(...);
|
||||
} )
|
||||
|
||||
#undef ESP_MODEM_DECLARE_DCE_COMMAND
|
||||
|
||||
@ -110,5 +127,3 @@ public:
|
||||
*/
|
||||
|
||||
} // esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_DCE_HPP_
|
@ -12,8 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_DCE_FACTORY_HPP_
|
||||
#define _ESP_MODEM_DCE_FACTORY_HPP_
|
||||
#pragma once
|
||||
#include "esp_log.h"
|
||||
|
||||
/**
|
||||
* @defgroup ESP_MODEM_DCE_FACTORY
|
||||
@ -31,83 +31,90 @@ using config = ::esp_modem_dce_config;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper class for creating a uder define pointer in a specific way, either as a plain pointer, shared_ptr or unique_ptr
|
||||
* @brief Helper class for creating a user define pointer in a specific way, either as a plain pointer, shared_ptr or unique_ptr
|
||||
*/
|
||||
class FactoryHelper {
|
||||
public:
|
||||
static std::unique_ptr<PdpContext> create_pdp_context(std::string &apn);
|
||||
|
||||
template <typename T, typename Ptr, typename ...Args>
|
||||
static auto make(Args&&... args) -> typename std::enable_if<std::is_same<Ptr, T*>::value, T*>::type
|
||||
template <typename T, typename T_Ptr, typename ...Args>
|
||||
static auto make(Args &&... args) -> typename std::enable_if<std::is_same<T_Ptr, T *>::value, T *>::type
|
||||
{
|
||||
return new T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename Ptr, typename ...Args>
|
||||
static auto make(Args&&... args) -> typename std::enable_if<std::is_same<Ptr, std::shared_ptr<T>>::value, std::shared_ptr<T>>::type
|
||||
template <typename T, typename T_Ptr, typename ...Args>
|
||||
static auto make(Args &&... args) -> typename std::enable_if<std::is_same<T_Ptr, std::shared_ptr<T>>::value, std::shared_ptr<T>>::type
|
||||
{
|
||||
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename Ptr = std::unique_ptr<T>, typename ...Args>
|
||||
static auto make(Args&&... args) -> typename std::enable_if<std::is_same<Ptr, std::unique_ptr<T>>::value, std::unique_ptr<T>>::type
|
||||
template <typename T, typename T_Ptr = std::unique_ptr<T>, typename ...Args>
|
||||
static auto make(Args && ... args) -> typename std::enable_if<std::is_same<T_Ptr, std::unique_ptr<T>>::value, std::unique_ptr<T>>::type
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder class for building a DCE_T<Module> in a specific way, either form a Module object or by default from the DTE and netif
|
||||
* @brief Creator class for building a DCE_T<Module> in a specific way, either from a Module object or by default from the DTE and netif
|
||||
*
|
||||
* @throws
|
||||
* - esp_modem::esp_err_exception on invalid arguments
|
||||
* - std::bad_alloc if failed to allocate
|
||||
*/
|
||||
template<typename Module>
|
||||
class Builder {
|
||||
static_assert(std::is_base_of<ModuleIf, Module>::value, "Builder must be used only for Module classes");
|
||||
template<typename T_Module>
|
||||
class Creator {
|
||||
static_assert(std::is_base_of<ModuleIf, T_Module>::value, "Builder must be used only for Module classes");
|
||||
public:
|
||||
Builder(std::shared_ptr<DTE> x, esp_netif_t* esp_netif): dte(std::move(x)), device(nullptr), netif(esp_netif)
|
||||
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");
|
||||
}
|
||||
|
||||
Builder(std::shared_ptr<DTE> dte, esp_netif_t* esp_netif, std::shared_ptr<Module> dev): dte(std::move(dte)), device(std::move(dev)), netif(esp_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");
|
||||
}
|
||||
|
||||
~Builder()
|
||||
~Creator()
|
||||
{
|
||||
throw_if_false(device == nullptr, "module was captured or created but never used");
|
||||
if (device != nullptr) {
|
||||
ESP_LOGE("dce_factory::~Creator", "module was captured or created but never used");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ptr>
|
||||
auto create_module(const esp_modem_dce_config *config) -> Ptr
|
||||
template<typename T_Ptr>
|
||||
auto create_module(const esp_modem_dce_config *config) -> T_Ptr
|
||||
{
|
||||
return FactoryHelper::make<Module, Ptr>(dte, config);
|
||||
return FactoryHelper::make<T_Module, T_Ptr>(dte, config);
|
||||
}
|
||||
|
||||
template<typename DceT, typename Ptr>
|
||||
auto create(const esp_modem_dce_config *config) -> Ptr
|
||||
template<typename T_Dce, typename T_Ptr>
|
||||
auto create(const esp_modem_dce_config *config) -> T_Ptr
|
||||
{
|
||||
if (dte == nullptr)
|
||||
if (dte == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (device == nullptr) {
|
||||
device = create_module<decltype(device)>(config);
|
||||
if (device == nullptr)
|
||||
if (device == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return FactoryHelper::make<DceT, Ptr>(std::move(dte), std::move(device), netif);
|
||||
return FactoryHelper::make<T_Dce, T_Ptr>(std::move(dte), std::move(device), netif);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<DTE> dte;
|
||||
std::shared_ptr<Module> device;
|
||||
std::shared_ptr<T_Module> device;
|
||||
esp_netif_t *netif;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specific modem choice when creating by the Factory
|
||||
*/
|
||||
enum class Modem {
|
||||
enum class ModemType {
|
||||
GenericModule, /*!< Default generic module with the most common commands */
|
||||
SIM7600, /*!< Derived from the GenericModule, specifics applied to SIM7600 model */
|
||||
BG96, /*!< Derived from the GenericModule, specifics applied to BG69 model */
|
||||
@ -120,7 +127,7 @@ enum class Modem {
|
||||
*/
|
||||
class Factory {
|
||||
public:
|
||||
explicit Factory(Modem modem): m(modem) {}
|
||||
explicit Factory(ModemType modem): m(modem) {}
|
||||
|
||||
/**
|
||||
* @brief Create a default unique_ptr DCE in a specific way (from the module)
|
||||
@ -130,10 +137,10 @@ public:
|
||||
* @param args typically a DTE object and a netif handle for PPP network
|
||||
* @return unique_ptr DCE of the created DCE on success
|
||||
*/
|
||||
template <typename Module, typename ...Args>
|
||||
static std::unique_ptr<DCE> build_unique(const config *cfg, Args&&... args)
|
||||
template <typename T_Module, typename ...Args>
|
||||
static std::unique_ptr<DCE> build_unique(const config *cfg, Args &&... args)
|
||||
{
|
||||
return build_generic_DCE<Module, DCE, std::unique_ptr<DCE>>(cfg, std::forward<Args>(args)...);
|
||||
return build_generic_DCE<T_Module, DCE, std::unique_ptr<DCE>>(cfg, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,34 +151,34 @@ public:
|
||||
* @param args typically a DTE object and a netif handle for PPP network
|
||||
* @return DCE pointer the created DCE on success
|
||||
*/
|
||||
template <typename Module, typename ...Args>
|
||||
static DCE* build(const config *cfg, Args&&... args)
|
||||
template <typename T_Module, typename ...Args>
|
||||
static DCE *build(const config *cfg, Args &&... args)
|
||||
{
|
||||
return build_generic_DCE<Module, DCE>(cfg, std::forward<Args>(args)...);
|
||||
return build_generic_DCE<T_Module, DCE>(cfg, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
template <typename Module, typename ...Args>
|
||||
static std::shared_ptr<Module> build_shared_module(const config *cfg, Args&&... args)
|
||||
template <typename T_Module, typename ...Args>
|
||||
static std::shared_ptr<T_Module> build_shared_module(const config *cfg, Args &&... args)
|
||||
{
|
||||
return build_module_T<Module>(cfg, std::forward<Args>(args)...);
|
||||
return build_module_T<T_Module>(cfg, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
template <typename ...Args>
|
||||
std::shared_ptr<GenericModule> build_shared_module(const config *cfg, Args&&... args)
|
||||
std::shared_ptr<GenericModule> build_shared_module(const config *cfg, Args &&... args)
|
||||
{
|
||||
switch (m) {
|
||||
case Modem::SIM800:
|
||||
return build_shared_module<SIM800>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::SIM7600:
|
||||
return build_shared_module<SIM7600>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::BG96:
|
||||
return build_shared_module<BG96>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::GenericModule:
|
||||
return build_shared_module<GenericModule>(cfg, std::forward<Args>(args)...);
|
||||
default:
|
||||
break;
|
||||
case ModemType::SIM800:
|
||||
return build_shared_module<SIM800>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::SIM7600:
|
||||
return build_shared_module<SIM7600>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::BG96:
|
||||
return build_shared_module<BG96>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::GenericModule:
|
||||
return build_shared_module<GenericModule>(cfg, std::forward<Args>(args)...);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -184,58 +191,58 @@ public:
|
||||
* @return unique_ptr DCE of the created DCE on success
|
||||
*/
|
||||
template <typename ...Args>
|
||||
std::unique_ptr<DCE> build_unique(const config *cfg, Args&&... args)
|
||||
std::unique_ptr<DCE> build_unique(const config *cfg, Args &&... args)
|
||||
{
|
||||
switch (m) {
|
||||
case Modem::SIM800:
|
||||
return build_unique<SIM800>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::SIM7600:
|
||||
return build_unique<SIM7600>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::BG96:
|
||||
return build_unique<BG96>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::GenericModule:
|
||||
return build_unique<GenericModule>(cfg, std::forward<Args>(args)...);
|
||||
default:
|
||||
break;
|
||||
case ModemType::SIM800:
|
||||
return build_unique<SIM800>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::SIM7600:
|
||||
return build_unique<SIM7600>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::BG96:
|
||||
return build_unique<BG96>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::GenericModule:
|
||||
return build_unique<GenericModule>(cfg, std::forward<Args>(args)...);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
DCE* build(const config *cfg, Args&&... args)
|
||||
DCE *build(const config *cfg, Args &&... args)
|
||||
{
|
||||
switch (m) {
|
||||
case Modem::SIM800:
|
||||
return build<SIM800>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::SIM7600:
|
||||
return build<SIM7600>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::BG96:
|
||||
return build<BG96>(cfg, std::forward<Args>(args)...);
|
||||
case Modem::GenericModule:
|
||||
return build<GenericModule>(cfg, std::forward<Args>(args)...);
|
||||
default:
|
||||
break;
|
||||
case ModemType::SIM800:
|
||||
return build<SIM800>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::SIM7600:
|
||||
return build<SIM7600>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::BG96:
|
||||
return build<BG96>(cfg, std::forward<Args>(args)...);
|
||||
case ModemType::GenericModule:
|
||||
return build<GenericModule>(cfg, std::forward<Args>(args)...);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Modem m;
|
||||
ModemType m;
|
||||
|
||||
protected:
|
||||
template <typename Module, typename Ptr = std::shared_ptr<Module>, typename ...Args>
|
||||
static Ptr build_module_T(const config *cfg, Args&&... args)
|
||||
template <typename T_Module, typename Ptr = std::shared_ptr<T_Module>, typename ...Args>
|
||||
static Ptr build_module_T(const config *cfg, Args && ... args)
|
||||
{
|
||||
Builder<Module> b(std::forward<Args>(args)...);
|
||||
return b.template create_module<Ptr>(cfg);
|
||||
Creator<T_Module> creator(std::forward<Args>(args)...);
|
||||
return creator.template create_module<Ptr>(cfg);
|
||||
}
|
||||
|
||||
|
||||
template <typename Module, typename Dce = DCE_T<Module>, typename DcePtr = Dce*, typename ...Args>
|
||||
static DcePtr build_generic_DCE(const config *cfg, Args&&... args)
|
||||
template <typename T_Module, typename T_Dce = DCE_T<T_Module>, typename T_DcePtr = T_Dce *, typename ...Args>
|
||||
static auto build_generic_DCE(const config *cfg, Args && ... args) -> T_DcePtr
|
||||
{
|
||||
Builder<Module> b(std::forward<Args>(args)...);
|
||||
return b.template create<Dce, DcePtr>(cfg);
|
||||
Creator<T_Module> creator(std::forward<Args>(args)...);
|
||||
return creator.template create<T_Dce, T_DcePtr>(cfg);
|
||||
}
|
||||
};
|
||||
|
||||
@ -244,6 +251,3 @@ protected:
|
||||
*/
|
||||
|
||||
} // namespace esp_modem::dce_factory
|
||||
|
||||
|
||||
#endif // _ESP_MODEM_DCE_FACTORY_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_DCE_MODULE_
|
||||
#define _ESP_MODEM_DCE_MODULE_
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
@ -48,8 +47,8 @@ public:
|
||||
* The configuration could be either the dce-config struct or just a pdp context
|
||||
*/
|
||||
explicit GenericModule(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp):
|
||||
dte(std::move(dte)), pdp(std::move(pdp)) {}
|
||||
explicit GenericModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config* config);
|
||||
dte(std::move(dte)), pdp(std::move(pdp)) {}
|
||||
explicit GenericModule(std::shared_ptr<DTE> dte, const esp_modem_dce_config *config);
|
||||
|
||||
/**
|
||||
* @brief This is a mandatory method for ModuleIf class, which sets up the device
|
||||
@ -59,10 +58,12 @@ public:
|
||||
*/
|
||||
bool setup_data_mode() override
|
||||
{
|
||||
if (set_echo(false) != command_result::OK)
|
||||
if (set_echo(false) != command_result::OK) {
|
||||
return false;
|
||||
if (set_pdp_context(*pdp) != command_result::OK)
|
||||
}
|
||||
if (set_pdp_context(*pdp) != command_result::OK) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -73,10 +74,12 @@ public:
|
||||
bool set_mode(modem_mode mode) override
|
||||
{
|
||||
if (mode == modem_mode::DATA_MODE) {
|
||||
if (set_data_mode() != command_result::OK)
|
||||
if (set_data_mode() != command_result::OK) {
|
||||
return resume_data_mode() == command_result::OK;
|
||||
}
|
||||
return true;
|
||||
} else if (mode == modem_mode::COMMAND_MODE) {
|
||||
Task::Delay(1000); // Mandatory 1s pause
|
||||
return set_command_mode() == command_result::OK;
|
||||
} else if (mode == modem_mode::CMUX_MODE) {
|
||||
return set_cmux() == command_result::OK;
|
||||
@ -116,8 +119,7 @@ protected:
|
||||
class SIM7600: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result get_module_name(std::string& name) override;
|
||||
command_result get_battery_status(int& voltage, int &bcs, int &bcl) override;
|
||||
command_result get_battery_status(int &voltage, int &bcs, int &bcl) override;
|
||||
command_result power_down() override;
|
||||
};
|
||||
|
||||
@ -127,7 +129,6 @@ public:
|
||||
class SIM800: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result get_module_name(std::string& name) override;
|
||||
command_result power_down() override;
|
||||
command_result set_data_mode() override;
|
||||
};
|
||||
@ -137,8 +138,6 @@ public:
|
||||
*/
|
||||
class BG96: public GenericModule {
|
||||
using GenericModule::GenericModule;
|
||||
public:
|
||||
command_result get_module_name(std::string& name) override;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -146,5 +145,3 @@ public:
|
||||
*/
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_DCE_MODULE_
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_DTE_HPP_
|
||||
#define _ESP_MODEM_DTE_HPP_
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
@ -117,5 +116,3 @@ private:
|
||||
*/
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_DTE_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_EXCEPTION_HPP_
|
||||
#define _ESP_MODEM_EXCEPTION_HPP_
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "esp_err.h"
|
||||
@ -27,9 +26,13 @@ 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() { return esp_err; }
|
||||
virtual esp_err_t get_err_t()
|
||||
{
|
||||
return esp_err;
|
||||
}
|
||||
~esp_err_exception() noexcept override = default;
|
||||
virtual const char* what() const noexcept {
|
||||
virtual const char *what() const noexcept
|
||||
{
|
||||
return message.c_str();
|
||||
}
|
||||
private:
|
||||
@ -62,5 +65,3 @@ static inline void throw_if_esp_fail(esp_err_t err)
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif //_ESP_MODEM_EXCEPTION_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_NETIF_HPP
|
||||
#define _ESP_MODEM_NETIF_HPP
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
@ -74,7 +73,7 @@ private:
|
||||
|
||||
std::shared_ptr<DTE> ppp_dte;
|
||||
esp_netif_t *netif;
|
||||
struct ppp_netif_driver driver{};
|
||||
struct ppp_netif_driver driver {};
|
||||
SignalGroup signal;
|
||||
static const size_t PPP_STARTED = SignalGroup::bit0;
|
||||
static const size_t PPP_EXIT = SignalGroup::bit1;
|
||||
@ -85,5 +84,3 @@ private:
|
||||
*/
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_NETIF_HPP
|
||||
|
@ -12,8 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_PRIMITIVES_HPP_
|
||||
#define _ESP_MODEM_PRIMITIVES_HPP_
|
||||
#pragma once
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "esp_modem_exception.hpp"
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_LINUX)
|
||||
@ -21,9 +22,9 @@
|
||||
#include <thread>
|
||||
|
||||
#else
|
||||
#include "freertos/event_groups.h"
|
||||
// forward declarations of FreeRTOS primitives
|
||||
struct QueueDefinition;
|
||||
typedef void * EventGroupHandle_t;
|
||||
#endif
|
||||
|
||||
|
||||
@ -31,10 +32,10 @@ namespace esp_modem {
|
||||
|
||||
// Forward declaration for both linux/FreeRTOS targets
|
||||
//
|
||||
using TaskFunction_t = void (*)(void*);
|
||||
using TaskFunction_t = void (*)(void *);
|
||||
#if !defined(CONFIG_IDF_TARGET_LINUX)
|
||||
struct Lock {
|
||||
using MutexT = QueueDefinition*;
|
||||
using MutexT = QueueHandle_t;
|
||||
explicit Lock();
|
||||
~Lock();
|
||||
void lock();
|
||||
@ -42,8 +43,8 @@ struct Lock {
|
||||
private:
|
||||
MutexT m{};
|
||||
};
|
||||
using TaskT = void*;
|
||||
using SignalT = void*;
|
||||
using TaskT = TaskHandle_t;
|
||||
using SignalT = EventGroupHandle_t;
|
||||
#else
|
||||
using Lock = std::mutex;
|
||||
struct SignalGroupInternal;
|
||||
@ -55,11 +56,17 @@ static constexpr uint32_t portMAX_DELAY = UINT32_MAX;
|
||||
template<class T>
|
||||
class Scoped {
|
||||
public:
|
||||
explicit Scoped(T &l):lock(l) { lock.lock(); }
|
||||
~Scoped() { lock.unlock(); }
|
||||
explicit Scoped(T &l): lock(l)
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
~Scoped()
|
||||
{
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
T& lock;
|
||||
T &lock;
|
||||
};
|
||||
|
||||
class Task {
|
||||
@ -69,6 +76,7 @@ public:
|
||||
|
||||
static void Delete();
|
||||
static void Relinquish();
|
||||
static void Delay(uint32_t delay);
|
||||
private:
|
||||
TaskT task_handle;
|
||||
};
|
||||
@ -102,5 +110,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_PRIMITIVES_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_TERMINAL_HPP_
|
||||
#define _ESP_MODEM_TERMINAL_HPP_
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
@ -45,15 +44,21 @@ enum class terminal_error {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Terminal interface. All communication interfaces must comply this interface in order to be used as a DTE
|
||||
* @brief Terminal interface. All communication interfaces must comply to this interface in order to be used as a DTE
|
||||
*/
|
||||
class Terminal {
|
||||
public:
|
||||
virtual ~Terminal() = default;
|
||||
|
||||
void set_error_cb(std::function<void(terminal_error)> f) { on_error = std::move(f); }
|
||||
void set_error_cb(std::function<void(terminal_error)> f)
|
||||
{
|
||||
on_error = std::move(f);
|
||||
}
|
||||
|
||||
virtual void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) { on_data = std::move(f); }
|
||||
virtual void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f)
|
||||
{
|
||||
on_read = std::move(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes data to the terminal
|
||||
@ -76,7 +81,7 @@ public:
|
||||
virtual void stop() = 0;
|
||||
|
||||
protected:
|
||||
std::function<bool(uint8_t *data, size_t len)> on_data;
|
||||
std::function<bool(uint8_t *data, size_t len)> on_read;
|
||||
std::function<void(terminal_error)> on_error;
|
||||
};
|
||||
|
||||
@ -85,5 +90,3 @@ protected:
|
||||
*/
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_TERMINAL_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_TYPES_HPP_
|
||||
#define _ESP_MODEM_TYPES_HPP_
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
@ -68,6 +67,12 @@ struct PdpContext {
|
||||
*/
|
||||
class CommandableIf {
|
||||
public:
|
||||
CommandableIf() = default;
|
||||
CommandableIf(const CommandableIf&) = delete;
|
||||
CommandableIf& operator=(const CommandableIf&) = delete;
|
||||
CommandableIf(CommandableIf&&) = delete;
|
||||
CommandableIf& operator=(CommandableIf&&) = delete;
|
||||
virtual ~CommandableIf() = default;
|
||||
/**
|
||||
* @brief Sends custom AT command
|
||||
* @param command Command to be sent
|
||||
@ -84,8 +89,14 @@ public:
|
||||
*/
|
||||
class ModuleIf {
|
||||
public:
|
||||
ModuleIf() = default;
|
||||
ModuleIf(const ModuleIf&) = delete;
|
||||
ModuleIf& operator=(const ModuleIf&) = delete;
|
||||
ModuleIf(ModuleIf&&) = delete;
|
||||
ModuleIf& operator=(ModuleIf&&) = delete;
|
||||
virtual ~ModuleIf() = default;
|
||||
/**
|
||||
* @brief Sets the data mode up (provides the necessary configuration to connect to the cellular network
|
||||
* @brief Sets the data mode up (provides the necessary configuration to connect to the cellular network)
|
||||
* @return true on success
|
||||
*/
|
||||
virtual bool setup_data_mode() = 0;
|
||||
@ -103,5 +114,3 @@ public:
|
||||
*/
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _ESP_MODEM_TYPES_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_API_H_
|
||||
#define _ESP_MODEM_API_H_
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "generate/esp_modem_command_declare.inc"
|
||||
@ -35,6 +34,3 @@ DECLARE_ALL_COMMAND_APIS(declares esp_modem_<API>(esp_modem_t * dce, ...);)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _CLIENT_ESP_MODEM_API_H_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_C_API_TYPES_H_
|
||||
#define _ESP_MODEM_C_API_TYPES_H_
|
||||
#pragma once
|
||||
|
||||
#include "esp_modem_config.h"
|
||||
|
||||
@ -98,5 +97,3 @@ esp_err_t esp_modem_set_mode(esp_modem_dce_t * dce, esp_modem_dce_mode_t mode);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //_ESP_MODEM_C_API_TYPES_H_
|
||||
|
@ -12,11 +12,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_CONFIG_H_
|
||||
#define _ESP_MODEM_CONFIG_H_
|
||||
#pragma once
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "esp_modem_dce_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup ESP_MODEM_CONFIG
|
||||
* @brief Configuration structures for DTE and DCE
|
||||
@ -56,23 +60,17 @@ struct esp_modem_uart_term_config {
|
||||
int event_queue_size; /*!< UART Event Queue Size, set to 0 if no event queue needed */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Resources used by VFS terminal
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_MODEM_VFS_IS_EXTERN = 0, /*!< External resource: internal VFS terminal takes no action to setup this */
|
||||
ESP_MODEM_VFS_IS_UART, /*!< VFS uses UART: internal VFS initializes UART based on esp_modem_uart_term_config */
|
||||
} esp_modem_vfs_resource_t;
|
||||
|
||||
// Forward declare the resource struct
|
||||
struct esp_modem_vfs_resource;
|
||||
|
||||
/**
|
||||
* @brief VFS configuration structure
|
||||
*
|
||||
*/
|
||||
struct esp_modem_vfs_term_config {
|
||||
const char* dev_name; /*!< VFS device name, e.g. /dev/uart/n */
|
||||
esp_modem_vfs_resource_t resource; /*!< Underlying device which gets initialized during VFS init */
|
||||
int fd; /*!< Already created file descriptor */
|
||||
void (*deleter)(int, struct esp_modem_vfs_resource*); /*!< Custom close function for the fd */
|
||||
struct esp_modem_vfs_resource *resource; /*!< Resource attached to the VFS (need for clenaup) */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -86,8 +84,10 @@ struct esp_modem_dte_config {
|
||||
size_t dte_buffer_size; /*!< DTE buffer size */
|
||||
uint32_t task_stack_size; /*!< Terminal task stack size */
|
||||
int task_priority; /*!< Terminal task priority */
|
||||
struct esp_modem_uart_term_config uart_config; /*!< Configuration for UART Terminal */
|
||||
struct esp_modem_vfs_term_config vfs_config; /*!< Configuration for VFS Terminal */
|
||||
union {
|
||||
struct esp_modem_uart_term_config uart_config; /*!< Configuration for UART Terminal */
|
||||
struct esp_modem_vfs_term_config vfs_config; /*!< Configuration for VFS Terminal */
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -115,10 +115,6 @@ struct esp_modem_dte_config {
|
||||
.tx_buffer_size = 512, \
|
||||
.event_queue_size = 30, \
|
||||
}, \
|
||||
.vfs_config = { \
|
||||
.dev_name = "/null", \
|
||||
.resource = ESP_MODEM_VFS_IS_EXTERN \
|
||||
}\
|
||||
}
|
||||
|
||||
typedef struct esp_modem_dte_config esp_modem_dte_config_t;
|
||||
@ -127,4 +123,6 @@ typedef struct esp_modem_dte_config esp_modem_dte_config_t;
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // _ESP_MODEM_CONFIG_H_
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -12,8 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_MODEM_DCE_CONFIG_H_
|
||||
#define _ESP_MODEM_DCE_CONFIG_H_
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @addtogroup ESP_MODEM_CONFIG
|
||||
* @{
|
||||
@ -41,5 +44,6 @@ struct esp_modem_dce_config {
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#endif // _ESP_MODEM_DCE_CONFIG_H_
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -29,14 +29,14 @@
|
||||
#define BOOL_OUT(param, name) bool& _ARG(param, name)
|
||||
#define INT_OUT(param, name) int& _ARG(param, name)
|
||||
|
||||
#define STRUCT_OUT(struct_name, x) struct_name& x
|
||||
#define STRUCT_OUT(struct_name, p1) struct_name& p1
|
||||
#else
|
||||
#define STRING_IN(param, name) const char* _ARG(param, name)
|
||||
#define STRING_OUT(param, name) char* _ARG(param, name)
|
||||
#define BOOL_IN(param, name) const bool _ARG(param, name)
|
||||
#define BOOL_OUT(param, name) bool* _ARG(param, name)
|
||||
#define INT_OUT(param, name) int* _ARG(param, name)
|
||||
#define STRUCT_OUT(struct_name, x) struct struct_name* x
|
||||
#define STRUCT_OUT(struct_name, p1) struct struct_name* p1
|
||||
#endif
|
||||
|
||||
#define DECLARE_ALL_COMMAND_APIS(...) \
|
||||
@ -50,7 +50,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(sync, command_result, 0) \
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 1, STRING_OUT(x, name)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 1, STRING_OUT(p1, name)) \
|
||||
\
|
||||
/**
|
||||
* @brief Stores current user profile
|
||||
@ -63,28 +63,28 @@ 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(x, pin)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
|
||||
\
|
||||
/**
|
||||
* @brief Checks if the SIM needs a PIN
|
||||
* @param[out] pin_ok true if the SIM card doesn't need a PIN to unlock
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(read_pin, command_result, 1, BOOL_OUT(x, pin_ok)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(read_pin, command_result, 1, BOOL_OUT(p1, pin_ok)) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets echo mode
|
||||
* @param[in] echo_on true if echo mode on (repeats the commands)
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_echo, command_result, 1, BOOL_IN(x, echo_on)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_echo, command_result, 1, BOOL_IN(p1, echo_on)) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets the Txt or Pdu mode for SMS (only txt is supported)
|
||||
* @param[in] txt true if txt mode
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(sms_txt_mode, command_result, 1, BOOL_IN(x, txt)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(sms_txt_mode, command_result, 1, BOOL_IN(p1, txt)) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets the default (GSM) charater set
|
||||
@ -98,7 +98,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(sms_character_set, command_result, 0) \
|
||||
* @param[in] message Text message to be sent
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(send_sms, command_result, 2, STRING_IN(x, number), STRING_IN(y, message)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(send_sms, command_result, 2, STRING_IN(p1, number), STRING_IN(p2, message)) \
|
||||
\
|
||||
/**
|
||||
* @brief Resumes data mode (Switches back to th data mode, which was temporarily suspended)
|
||||
@ -108,10 +108,10 @@ ESP_MODEM_DECLARE_DCE_COMMAND(resume_data_mode, command_result, 0) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets php context
|
||||
* @param[in] x PdP context struct to setup modem cellular connection
|
||||
* @param[in] p1 PdP context struct to setup modem cellular connection
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_pdp_context, command_result, 1, STRUCT_OUT(PdpContext, x)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_pdp_context, command_result, 1, STRUCT_OUT(PdpContext, p1)) \
|
||||
\
|
||||
/**
|
||||
* @brief Switches to the command mode
|
||||
@ -130,21 +130,21 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_cmux, command_result, 0) \
|
||||
* @param[out] imsi Module's IMSI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_imsi, command_result, 1, STRING_OUT(x, imsi)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_imsi, command_result, 1, STRING_OUT(p1, imsi)) \
|
||||
\
|
||||
/**
|
||||
* @brief Reads the IMEI number
|
||||
* @param[out] imei Module's IMEI number
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_imei, command_result, 1, STRING_OUT(x, imei)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_imei, command_result, 1, STRING_OUT(p1, imei)) \
|
||||
\
|
||||
/**
|
||||
* @brief Reads the module name
|
||||
* @param[out] name module name
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_module_name, command_result, 1, STRING_OUT(x, name)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_module_name, command_result, 1, STRING_OUT(p1, name)) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets the modem to data mode
|
||||
@ -158,7 +158,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_data_mode, command_result, 0) \
|
||||
* @param[out] ber channel bit error rate
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_signal_quality, command_result, 2, INT_OUT(x, rssi), INT_OUT(y, ber)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_signal_quality, command_result, 2, INT_OUT(p1, rssi), INT_OUT(p2, ber)) \
|
||||
\
|
||||
/**
|
||||
* @brief Sets HW control flow
|
||||
@ -166,7 +166,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(get_signal_quality, command_result, 2, INT_OUT(x,
|
||||
* @param[in] dte_flow 0=none, 2=CTS hw flow control of DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_flow_control, command_result, 2, INT_IN(x, dce_flow), INT_IN(y, dte_flow)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_flow_control, command_result, 2, INT_IN(p1, dce_flow), INT_IN(p2, dte_flow)) \
|
||||
\
|
||||
/**
|
||||
* @brief Hangs up current data call
|
||||
@ -181,7 +181,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(hang_up, command_result, 0) \
|
||||
* @param[out] bcl 1-100% battery capacity, -1-Not available
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_battery_status, command_result, 3, INT_OUT(x, voltage), INT_OUT(y, bcs), INT_OUT(z, bcl)) \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(get_battery_status, command_result, 3, INT_OUT(p1, voltage), INT_OUT(p2, bcs), INT_OUT(p3, bcl)) \
|
||||
\
|
||||
/**
|
||||
* @brief Power down the module
|
||||
@ -193,14 +193,14 @@ ESP_MODEM_DECLARE_DCE_COMMAND(power_down, command_result, 0) \
|
||||
* @brief Reset the module
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(reset, command_result, 0)\
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(reset, command_result, 0) \
|
||||
\
|
||||
/**
|
||||
* @brief Configures the baudrate
|
||||
* @param[in] baud Desired baud rate of the DTE
|
||||
* @return OK, FAIL or TIMEOUT
|
||||
*/ \
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_baud, command_result, 1, INT_IN(x, baud))
|
||||
ESP_MODEM_DECLARE_DCE_COMMAND(set_baud, command_result, 1, INT_IN(p1, baud))
|
||||
|
||||
|
||||
#ifdef GENERATE_DOCS
|
||||
@ -213,7 +213,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_baud, command_result, 1, INT_IN(x, baud))
|
||||
#define _ARG(param, name) name
|
||||
// --- DCE command documentation starts here ---
|
||||
#ifdef __cplusplus
|
||||
class esp_modem::DCE: public DCE_T<GenericModule> {
|
||||
class esp_modem::DCE : public DCE_T<GenericModule> {
|
||||
public:
|
||||
using DCE_T<GenericModule>::DCE_T;
|
||||
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, TEMPLATE_ARG, ...) return_type name (__VA_ARGS__);
|
||||
|
68
components/esp_modem/include/vfs_resource/vfs_create.hpp
Normal file
68
components/esp_modem/include/vfs_resource/vfs_create.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ESP_MODEM_VFS_DEFAULT_UART_CONFIG(name) { \
|
||||
.dev_name = (name), \
|
||||
.uart = { \
|
||||
.port_num = UART_NUM_1, \
|
||||
.data_bits = UART_DATA_8_BITS, \
|
||||
.stop_bits = UART_STOP_BITS_1, \
|
||||
.parity = UART_PARITY_DISABLE, \
|
||||
.flow_control = ESP_MODEM_FLOW_CONTROL_NONE,\
|
||||
.baud_rate = 115200, \
|
||||
.tx_io_num = 25, \
|
||||
.rx_io_num = 26, \
|
||||
.rts_io_num = 27, \
|
||||
.cts_io_num = 23, \
|
||||
.rx_buffer_size = 4096, \
|
||||
.tx_buffer_size = 512, \
|
||||
.event_queue_size = 0, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART init struct for VFS
|
||||
*/
|
||||
struct esp_modem_vfs_uart_creator {
|
||||
const char *dev_name; /*!< VFS device name, e.g. /dev/uart/n */
|
||||
const struct esp_modem_uart_term_config uart; /*!< UART driver init struct */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief UART init struct for VFS
|
||||
*/
|
||||
struct esp_modem_vfs_socket_creator {
|
||||
const char *host_name; /*!< VFS socket: host name (or IP address) */
|
||||
int port; /*!< VFS socket: port number */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a socket VFS and configures the DTE struct
|
||||
*
|
||||
* @param config Socket config option, basically host + port
|
||||
* @param created_config reference to the VFS portion of the DTE config to be set up
|
||||
* @return true on success
|
||||
*/
|
||||
bool vfs_create_socket(struct esp_modem_vfs_socket_creator *config, struct esp_modem_vfs_term_config *created_config);
|
||||
|
||||
/**
|
||||
* @brief Creates a uart VFS and configures the DTE struct
|
||||
*
|
||||
* @param config Uart config option, basically file name and console options
|
||||
* @param created_config reference to the VFS portion of the DTE config to be set up
|
||||
* @return true on success
|
||||
*/
|
||||
bool vfs_create_uart(struct esp_modem_vfs_uart_creator *config, struct esp_modem_vfs_term_config *created_config);
|
@ -11,8 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MDNS_HOST_ESP_EVENT_H
|
||||
#define MDNS_HOST_ESP_EVENT_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_netif.h"
|
||||
@ -38,4 +37,4 @@ esp_err_t esp_event_handler_register(const char * event_base, int32_t event_id,
|
||||
|
||||
esp_err_t esp_event_handler_unregister(const char * event_base, int32_t event_id, void* event_handler);
|
||||
|
||||
#endif //MDNS_HOST_ESP_EVENT_H
|
||||
typedef void * QueueHandle_t;
|
||||
|
@ -11,8 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MDNS_HOST_ESP_EVENT_BASE_H
|
||||
#define MDNS_HOST_ESP_EVENT_BASE_H
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
WIFI_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */
|
||||
@ -25,4 +24,3 @@ typedef enum {
|
||||
|
||||
typedef void * esp_event_base_t;
|
||||
|
||||
#endif //MDNS_HOST_ESP_EVENT_BASE_H
|
||||
|
@ -3,18 +3,20 @@ set(LWIP_CONTRIB_DIR "$ENV{LWIP_CONTRIB_PATH}")
|
||||
|
||||
set(lwipcontribportunix_SRCS ${LWIP_CONTRIB_DIR}/ports/unix/port/sys_arch.c)
|
||||
|
||||
include(${LWIP_DIR}/src/Filelists.cmake)
|
||||
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
|
||||
set (LWIP_INCLUDE_DIRS
|
||||
include(${LWIP_DIR}/src/Filelists.cmake)
|
||||
|
||||
set (LWIP_INCLUDE_DIRS
|
||||
"${LWIP_DIR}/src/include"
|
||||
"${LWIP_CONTRIB_DIR}/ports/unix/port/include")
|
||||
|
||||
list(REMOVE_ITEM lwipnoapps_SRCS "${LWIP_DIR}/src/netif/slipif.c")
|
||||
list(REMOVE_ITEM lwipnoapps_SRCS "${LWIP_DIR}/src/core/ip4.c")
|
||||
list(REMOVE_ITEM lwipnoapps_SRCS "${LWIP_DIR}/src/core/ipv6/ip6.c")
|
||||
list(REMOVE_ITEM lwipnoapps_SRCS "${LWIP_DIR}/src/netif/slipif.c")
|
||||
list(REMOVE_ITEM lwipnoapps_SRCS "${LWIP_DIR}/src/core/ipv4/ip4.c")
|
||||
list(REMOVE_ITEM lwipnoapps_SRCS "${LWIP_DIR}/src/core/ipv6/ip6.c")
|
||||
endif()
|
||||
|
||||
|
||||
idf_component_register(SRCS esp_netif_linux.cpp tun_io.c ip6_stub.c ${lwipnoapps_SRCS} ${lwipcontribportunix_SRCS}
|
||||
idf_component_register(SRCS esp_netif_linux.cpp tun_io.c ip4_stub.c ip6_stub.c ${lwipnoapps_SRCS} ${lwipcontribportunix_SRCS}
|
||||
INCLUDE_DIRS include ${LWIP_INCLUDE_DIRS}
|
||||
PRIV_INCLUDE_DIRS .
|
||||
REQUIRES esp_system_protocols_linux)
|
||||
|
@ -35,8 +35,7 @@ class NetifStorage;
|
||||
|
||||
void read_task(NetifStorage *netif);
|
||||
|
||||
class NetifStorage: public esp_netif_obj
|
||||
{
|
||||
class NetifStorage: public esp_netif_obj {
|
||||
public:
|
||||
explicit NetifStorage(const esp_netif_config_t *config) : esp_netif_obj(), exit(false)
|
||||
{
|
||||
@ -91,46 +90,9 @@ public:
|
||||
extern "C" esp_netif_t *esp_netif_new(const esp_netif_config_t *config)
|
||||
{
|
||||
return new NetifStorage(config);
|
||||
// struct ifreq ifr = { };
|
||||
// esp_netif_t * netif = netif_storage;
|
||||
// if (netif == NULL) {
|
||||
// return NULL;
|
||||
// }
|
||||
// if ((netif->fd = open(config->dev_name, O_RDWR)) == -1) {
|
||||
// ESP_LOGE(TAG, "Cannot open %s", config->dev_name);
|
||||
// goto cleanup;
|
||||
// }
|
||||
// ifr.ifr_flags = IFF_TUN;
|
||||
// strncpy(ifr.ifr_name, config->if_name, IFNAMSIZ);
|
||||
//
|
||||
// if (ioctl(netif->fd, TUNSETIFF, (void *)&ifr) == -1) {
|
||||
// ESP_LOGE(TAG, "Cannot set ioctl TUNSETIFF %m");
|
||||
// goto cleanup;
|
||||
// }
|
||||
// ioctl(netif->fd, TUNSETNOCSUM, 1);
|
||||
//
|
||||
// netif->in_buf = new uint8_t[BUF_SIZE];
|
||||
// netif->out_buf = new uint8_t[BUF_SIZE];
|
||||
// if (netif->in_buf == nullptr || netif->out_buf == nullptr) {
|
||||
// goto cleanup;
|
||||
// }
|
||||
//
|
||||
// if (!ppp_netif_init(netif)) {
|
||||
// ESP_LOGE(TAG, "Cannot initialize pppos lwip netif %m");
|
||||
// goto cleanup;
|
||||
// }
|
||||
//
|
||||
// return netif;
|
||||
//
|
||||
//cleanup:
|
||||
// close(netif->fd);
|
||||
// delete[] netif->in_buf;
|
||||
// delete[] netif->out_buf;
|
||||
// delete netif_storage;
|
||||
// return nullptr;
|
||||
}
|
||||
|
||||
void esp_netif_destroy(esp_netif_t *netif)
|
||||
{
|
||||
delete static_cast<NetifStorage*>(netif);
|
||||
delete static_cast<NetifStorage *>(netif);
|
||||
}
|
||||
|
@ -11,8 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _HOST_ESP_NETIF_H_
|
||||
#define _HOST_ESP_NETIF_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@ -63,5 +62,3 @@ void esp_netif_destroy(esp_netif_t *esp_netif);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HOST_ESP_NETIF_H_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP_NETIF_IP_ADDR_H_
|
||||
#define _ESP_NETIF_IP_ADDR_H_
|
||||
#pragma once
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
@ -164,5 +163,3 @@ esp_ip6_addr_type_t esp_netif_ip6_get_addr_type(esp_ip6_addr_t* ip6_addr);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //_ESP_NETIF_IP_ADDR_H_
|
||||
|
@ -13,10 +13,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#ifndef _ESP_NETIF_PPP_H_
|
||||
#define _ESP_NETIF_PPP_H_
|
||||
#pragma once
|
||||
|
||||
#define NETIF_PP_PHASE_OFFSET 0x100
|
||||
|
||||
|
||||
#endif //_ESP_NETIF_PPP_H_
|
||||
|
17
components/esp_modem/port/linux/esp_netif_linux/ip4_stub.c
Normal file
17
components/esp_modem/port/linux/esp_netif_linux/ip4_stub.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include "lwip/ip4.h"
|
||||
|
||||
err_t
|
||||
ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
|
||||
u8_t ttl, u8_t tos,
|
||||
u8_t proto, struct netif *netif)
|
||||
{ return ERR_OK; }
|
||||
|
||||
struct netif *
|
||||
ip4_route(const ip4_addr_t *dest)
|
||||
{ return NULL; }
|
||||
|
||||
err_t
|
||||
ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
|
||||
u8_t ttl, u8_t tos,
|
||||
u8_t proto, struct netif *netif)
|
||||
{ return ERR_OK; }
|
@ -12,6 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int uart_port_t;
|
||||
typedef int uart_word_length_t;
|
||||
|
@ -11,6 +11,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef int esp_err_t;
|
||||
|
||||
#define ESP_FAIL -1
|
||||
|
@ -11,8 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MDNS_HOST_ESP_LOG_H
|
||||
#define MDNS_HOST_ESP_LOG_H
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -46,4 +45,3 @@ printf(LOG_COLOR_D); printf("(%s) ", TAG); printf(__VA_ARGS__); printf(LOG_RESET
|
||||
#define ESP_LOGV(TAG, ...) do { \
|
||||
printf(LOG_COLOR_V); printf("(%s) ", TAG); printf(__VA_ARGS__); printf(LOG_RESET_COLOR "\n"); } while(0)
|
||||
|
||||
#endif //MDNS_HOST_ESP_LOG_H
|
||||
|
@ -11,9 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MDNS_HOST_ENDIAN_H
|
||||
#define MDNS_HOST_ENDIAN_H
|
||||
#pragma once
|
||||
|
||||
#include_next "endian.h"
|
||||
|
||||
#endif //MDNS_HOST_ENDIAN_H
|
||||
|
8
components/esp_modem/pre_upload.sh
Normal file
8
components/esp_modem/pre_upload.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
apt-get update
|
||||
apt-get -y install doxygen clang python3-pip
|
||||
python -m pip install breathe recommonmark
|
||||
pushd components/esp_modem/docs
|
||||
./generate_docs
|
||||
popd
|
@ -12,25 +12,28 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _EXCEPTION_STUB_HPP_
|
||||
#define _EXCEPTION_STUB_HPP_
|
||||
#pragma once
|
||||
|
||||
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
#define TRY_CATCH_RET_NULL(block) \
|
||||
#define TRY_CATCH_OR_DO(block, action) \
|
||||
try { block \
|
||||
} catch (std::bad_alloc& e) { \
|
||||
ESP_LOGE(TAG, "Out of memory"); \
|
||||
return nullptr; \
|
||||
} catch (esp_err_exception& e) { \
|
||||
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", e.what()); \
|
||||
return nullptr; \
|
||||
action; \
|
||||
}
|
||||
|
||||
#define TRY_CATCH_RET_NULL(block) TRY_CATCH_OR_DO(block, return nullptr)
|
||||
#else
|
||||
|
||||
#define TRY_CATCH_OR_DO(block, action) \
|
||||
block
|
||||
|
||||
#define TRY_CATCH_RET_NULL(block) \
|
||||
block
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _EXCEPTION_STUB_HPP_
|
||||
|
32
components/esp_modem/private_include/uart_compat.h
Normal file
32
components/esp_modem/private_include/uart_compat.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
/**
|
||||
* @brief This is a compatible header, which just takes care of different data ptr type
|
||||
* across different IDF version in driver/uart
|
||||
*/
|
||||
static inline int uart_write_bytes_compat(uart_port_t uart_num, const void* src, size_t size)
|
||||
{
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 3
|
||||
const void *data = src;
|
||||
#else
|
||||
auto *data = reinterpret_cast<const char*>(src);
|
||||
#endif
|
||||
return uart_write_bytes(uart_num, data, size);
|
||||
}
|
@ -12,13 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _UART_RESOURCE_HPP_
|
||||
#define _UART_RESOURCE_HPP_
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "esp_modem_config.h"
|
||||
|
||||
struct esp_modem_dte_config;
|
||||
struct esp_modem_uart_term_config;
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
@ -26,13 +25,12 @@ namespace esp_modem {
|
||||
* @brief Uart Resource is a platform specific struct which is implemented separately for ESP_PLATFORM and linux target
|
||||
*/
|
||||
struct uart_resource {
|
||||
explicit uart_resource(const esp_modem_dte_config *config, struct QueueDefinition** event_queue, int fd);
|
||||
explicit uart_resource(const esp_modem_uart_term_config *config, QueueHandle_t *event_queue, int fd);
|
||||
|
||||
~uart_resource();
|
||||
|
||||
uart_port_t port{};
|
||||
};
|
||||
|
||||
std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config);
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _UART_RESOURCE_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _UART_TERMINAL_HPP_
|
||||
#define _UART_TERMINAL_HPP_
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
|
||||
@ -25,4 +24,3 @@ std::unique_ptr<Terminal> create_uart_terminal(const esp_modem_dte_config *confi
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _UART_TERMINAL_HPP_
|
||||
|
@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _VFS_TERMINAL_HPP_
|
||||
#define _VFS_TERMINAL_HPP_
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
|
||||
@ -24,5 +23,3 @@ namespace esp_modem {
|
||||
std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config);
|
||||
|
||||
} // namespace esp_modem
|
||||
|
||||
#endif // _VFS_TERMINAL_HPP_
|
||||
|
@ -30,43 +30,43 @@ struct PdpContext;
|
||||
static const char *TAG = "modem_api";
|
||||
#endif
|
||||
|
||||
std::shared_ptr<DTE> create_uart_dte(const dte_config *config) {
|
||||
TRY_CATCH_RET_NULL(
|
||||
auto term = create_uart_terminal(config);
|
||||
return std::make_shared<DTE>(config, std::move(term));
|
||||
)
|
||||
}
|
||||
|
||||
std::shared_ptr<DTE> create_vfs_dte(const dte_config *config) {
|
||||
std::shared_ptr<DTE> create_vfs_dte(const dte_config *config)
|
||||
{
|
||||
TRY_CATCH_RET_NULL(
|
||||
auto term = create_vfs_terminal(config);
|
||||
return std::make_shared<DTE>(config, std::move(term));
|
||||
auto term = create_vfs_terminal(config);
|
||||
return std::make_shared<DTE>(config, std::move(term));
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
static inline std::unique_ptr<DCE>
|
||||
create_modem_dce(dce_factory::Modem m, const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif) {
|
||||
create_modem_dce(dce_factory::ModemType m, const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
|
||||
{
|
||||
dce_factory::Factory f(m);
|
||||
TRY_CATCH_RET_NULL(
|
||||
return f.build_unique(config, std::move(dte), netif);
|
||||
return f.build_unique(config, std::move(dte), netif);
|
||||
)
|
||||
}
|
||||
|
||||
std::unique_ptr<DCE> create_SIM7600_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif) {
|
||||
return create_modem_dce(dce_factory::Modem::SIM7600, config, std::move(dte), netif);
|
||||
std::unique_ptr<DCE> create_SIM7600_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
|
||||
{
|
||||
return create_modem_dce(dce_factory::ModemType::SIM7600, config, std::move(dte), netif);
|
||||
}
|
||||
|
||||
std::unique_ptr<DCE> create_SIM800_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif) {
|
||||
return create_modem_dce(dce_factory::Modem::SIM800, config, std::move(dte), netif);
|
||||
std::unique_ptr<DCE> create_SIM800_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
|
||||
{
|
||||
return create_modem_dce(dce_factory::ModemType::SIM800, config, std::move(dte), netif);
|
||||
}
|
||||
|
||||
std::unique_ptr<DCE> create_BG96_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif) {
|
||||
return create_modem_dce(dce_factory::Modem::BG96, config, std::move(dte), netif);
|
||||
std::unique_ptr<DCE> create_BG96_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
|
||||
{
|
||||
return create_modem_dce(dce_factory::ModemType::BG96, config, std::move(dte), netif);
|
||||
}
|
||||
|
||||
std::unique_ptr<DCE> create_generic_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif) {
|
||||
return create_modem_dce(dce_factory::Modem::GenericModule, config, std::move(dte), netif);
|
||||
std::unique_ptr<DCE> create_generic_dce(const dce_config *config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
|
||||
{
|
||||
return create_modem_dce(dce_factory::ModemType::GenericModule, config, std::move(dte), netif);
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
|
39
components/esp_modem/src/esp_modem_api_target.cpp
Normal file
39
components/esp_modem/src/esp_modem_api_target.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cassert>
|
||||
#include "esp_log.h"
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "uart_terminal.hpp"
|
||||
#include "vfs_termial.hpp"
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "cxx_include/esp_modem_dce_factory.hpp"
|
||||
#include "esp_modem_config.h"
|
||||
#include "exception_stub.hpp"
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
static const char *TAG = "modem_api_target";
|
||||
#endif
|
||||
|
||||
std::shared_ptr<DTE> create_uart_dte(const dte_config *config)
|
||||
{
|
||||
TRY_CATCH_RET_NULL(
|
||||
auto term = create_uart_terminal(config);
|
||||
return std::make_shared<DTE>(config, std::move(term));
|
||||
)
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
@ -23,50 +23,58 @@
|
||||
#include "exception_stub.hpp"
|
||||
#include "cstring"
|
||||
|
||||
#ifndef ESP_MODEM_C_API_STR_MAX
|
||||
#define ESP_MODEM_C_API_STR_MAX 64
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *dest, const char *src, size_t len);
|
||||
#endif
|
||||
|
||||
//
|
||||
// C API definitions
|
||||
using namespace esp_modem;
|
||||
|
||||
struct esp_modem_dce_wrap // need to mimic the polymorphic dispatch as CPP uses templated dispatch
|
||||
{
|
||||
struct esp_modem_dce_wrap { // need to mimic the polymorphic dispatch as CPP uses templated dispatch
|
||||
enum class modem_wrap_dte_type { UART, } dte_type;
|
||||
dce_factory::Modem modem_type;
|
||||
DCE* dce;
|
||||
dce_factory::ModemType modem_type;
|
||||
DCE *dce;
|
||||
};
|
||||
|
||||
static inline esp_err_t command_response_to_esp_err(command_result res)
|
||||
{
|
||||
switch (res) {
|
||||
case command_result::OK:
|
||||
return ESP_OK;
|
||||
case command_result::FAIL:
|
||||
return ESP_FAIL;
|
||||
case command_result::TIMEOUT:
|
||||
return ESP_ERR_TIMEOUT;
|
||||
case command_result::OK:
|
||||
return ESP_OK;
|
||||
case command_result::FAIL:
|
||||
return ESP_FAIL;
|
||||
case command_result::TIMEOUT:
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
static inline dce_factory::Modem convert_modem_enum(esp_modem_dce_device_t module)
|
||||
static inline dce_factory::ModemType convert_modem_enum(esp_modem_dce_device_t module)
|
||||
{
|
||||
switch (module) {
|
||||
case ESP_MODEM_DCE_SIM7600:
|
||||
return esp_modem::dce_factory::Modem::SIM7600;
|
||||
case ESP_MODEM_DCE_BG96:
|
||||
return esp_modem::dce_factory::Modem::BG96;
|
||||
case ESP_MODEM_DCE_SIM800:
|
||||
return esp_modem::dce_factory::Modem::SIM800;
|
||||
default:
|
||||
case ESP_MODEM_DCE_GENETIC:
|
||||
return esp_modem::dce_factory::Modem::GenericModule;
|
||||
case ESP_MODEM_DCE_SIM7600:
|
||||
return esp_modem::dce_factory::ModemType::SIM7600;
|
||||
case ESP_MODEM_DCE_BG96:
|
||||
return esp_modem::dce_factory::ModemType::BG96;
|
||||
case ESP_MODEM_DCE_SIM800:
|
||||
return esp_modem::dce_factory::ModemType::SIM800;
|
||||
default:
|
||||
case ESP_MODEM_DCE_GENETIC:
|
||||
return esp_modem::dce_factory::ModemType::GenericModule;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" esp_modem_dce_t *esp_modem_new_dev(esp_modem_dce_device_t module, const esp_modem_dte_config_t *dte_config, const esp_modem_dce_config_t *dce_config, esp_netif_t *netif)
|
||||
{
|
||||
auto dce_wrap = new (std::nothrow) esp_modem_dce_wrap;
|
||||
if (dce_wrap == nullptr)
|
||||
if (dce_wrap == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
auto dte = create_uart_dte(dte_config);
|
||||
if (dte == nullptr) {
|
||||
delete dce_wrap;
|
||||
@ -88,7 +96,7 @@ extern "C" esp_modem_dce_t *esp_modem_new(const esp_modem_dte_config_t *dte_conf
|
||||
return esp_modem_new_dev(ESP_MODEM_DCE_GENETIC, dte_config, dce_config, netif);
|
||||
}
|
||||
|
||||
extern "C" void esp_modem_destroy(esp_modem_dce_t * dce_wrap)
|
||||
extern "C" void esp_modem_destroy(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap) {
|
||||
delete dce_wrap->dce;
|
||||
@ -96,10 +104,11 @@ extern "C" void esp_modem_destroy(esp_modem_dce_t * dce_wrap)
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t * dce_wrap, esp_modem_dce_mode_t mode)
|
||||
extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce_mode_t mode)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (mode == ESP_MODEM_MODE_DATA) {
|
||||
dce_wrap->dce->set_data();
|
||||
} else if (mode == ESP_MODEM_MODE_COMMAND) {
|
||||
@ -110,62 +119,147 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t * dce_wrap, esp_modem_dc
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_read_pin(esp_modem_dce_t * dce_wrap, bool *pin)
|
||||
extern "C" esp_err_t esp_modem_read_pin(esp_modem_dce_t *dce_wrap, bool *pin)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return command_response_to_esp_err(dce_wrap->dce->read_pin(*pin));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_sms_txt_mode(esp_modem_dce_t * dce_wrap, bool txt)
|
||||
extern "C" esp_err_t esp_modem_sms_txt_mode(esp_modem_dce_t *dce_wrap, bool txt)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return command_response_to_esp_err(dce_wrap->dce->sms_txt_mode(txt));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_send_sms(esp_modem_dce_t * dce_wrap, const char * number, const char * message)
|
||||
extern "C" esp_err_t esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string number_str(number);
|
||||
std::string message_str(message);
|
||||
return command_response_to_esp_err(dce_wrap->dce->send_sms(number_str, message_str));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_sms_character_set(esp_modem_dce_t * dce_wrap)
|
||||
extern "C" esp_err_t esp_modem_sms_character_set(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return command_response_to_esp_err(dce_wrap->dce->sms_character_set());
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_pin(esp_modem_dce_t * dce_wrap, const char *pin)
|
||||
extern "C" esp_err_t esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string pin_str(pin);
|
||||
return command_response_to_esp_err(dce_wrap->dce->set_pin(pin_str));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_signal_quality(esp_modem_dce_t * dce_wrap, int *rssi, int *ber)
|
||||
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)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->get_signal_quality(*rssi, *ber));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_imsi(esp_modem_dce_t * dce_wrap, char *p_imsi)
|
||||
extern "C" esp_err_t esp_modem_get_imsi(esp_modem_dce_t *dce_wrap, char *p_imsi)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr)
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string imsi;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_imsi(imsi));
|
||||
if (ret == ESP_OK && !imsi.empty()) {
|
||||
strcpy(p_imsi, imsi.c_str());
|
||||
strlcpy(p_imsi, imsi.c_str(), ESP_MODEM_C_API_STR_MAX);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_flow_control(esp_modem_dce_t *dce_wrap, int dce_flow, int dte_flow)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->set_flow_control(dce_flow, dte_flow));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_store_profile(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->store_profile());
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_imei(esp_modem_dce_t *dce_wrap, char *p_imei)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string imei;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_imei(imei));
|
||||
if (ret == ESP_OK && !imei.empty()) {
|
||||
strlcpy(p_imei, imei.c_str(), ESP_MODEM_C_API_STR_MAX);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_operator_name(esp_modem_dce_t *dce_wrap, char *p_name)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string name;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_operator_name(name));
|
||||
if (ret == ESP_OK && !name.empty()) {
|
||||
strlcpy(p_name, name.c_str(), ESP_MODEM_C_API_STR_MAX);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_module_name(esp_modem_dce_t *dce_wrap, char *p_name)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
std::string name;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_module_name(name));
|
||||
if (ret == ESP_OK && !name.empty()) {
|
||||
strlcpy(p_name, name.c_str(), ESP_MODEM_C_API_STR_MAX);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_get_battery_status(esp_modem_dce_t *dce_wrap, int *p_volt, int *p_bcs, int *p_bcl)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr || p_bcs == nullptr || p_bcl == nullptr || p_volt == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int bcs, bcl, volt;
|
||||
auto ret = command_response_to_esp_err(dce_wrap->dce->get_battery_status(volt, bcs, bcl));
|
||||
if (ret == ESP_OK) {
|
||||
*p_volt = volt;
|
||||
*p_bcs = bcs;
|
||||
*p_bcl = bcl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_power_down(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->power_down());
|
||||
}
|
||||
|
@ -91,11 +91,21 @@ void CMux::send_sabm(size_t i)
|
||||
}
|
||||
|
||||
|
||||
struct CMux::CMuxFrame {
|
||||
uint8_t *ptr; /*!< pointer to the currently processing byte of the CMUX frame */
|
||||
size_t len; /*!< length of available data in the current CMUX frame */
|
||||
void advance(int size = 1)
|
||||
{
|
||||
ptr += size;
|
||||
len -= size;
|
||||
}
|
||||
};
|
||||
|
||||
void CMux::data_available(uint8_t *data, size_t len)
|
||||
{
|
||||
if (data && type == 0xFF && len > 0 && dlci > 0) {
|
||||
int virtual_term = dlci - 1;
|
||||
if (virtual_term < max_terms && read_cb[virtual_term]) {
|
||||
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
|
||||
// Post partial data (or defragment to post on CMUX footer)
|
||||
#ifdef DEFRAGMENT_CMUX_PAYLOAD
|
||||
if (payload_start == nullptr) {
|
||||
@ -112,15 +122,126 @@ void CMux::data_available(uint8_t *data, size_t len)
|
||||
sabm_ack = dlci;
|
||||
} else if (data == nullptr) {
|
||||
int virtual_term = dlci - 1;
|
||||
if (virtual_term < max_terms && read_cb[virtual_term]) {
|
||||
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
|
||||
#ifdef DEFRAGMENT_CMUX_PAYLOAD
|
||||
read_cb[virtual_term](payload_start, total_payload_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool CMux::on_init(CMuxFrame &frame)
|
||||
{
|
||||
if (frame.ptr[0] != SOF_MARKER) {
|
||||
ESP_LOGW("CMUX", "Protocol mismatch: Missed leading SOF, recovering...");
|
||||
state = cmux_state::RECOVER;
|
||||
return true;
|
||||
}
|
||||
if (frame.len > 1 && frame.ptr[1] == SOF_MARKER) {
|
||||
// empty frame
|
||||
frame.advance();
|
||||
return true;
|
||||
}
|
||||
state = cmux_state::HEADER;
|
||||
frame.advance();
|
||||
frame_header_offset = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMux::on_recovery(CMuxFrame &frame)
|
||||
{
|
||||
uint8_t *recover_ptr;
|
||||
if (frame.ptr[0] == SOF_MARKER) {
|
||||
// already init state
|
||||
state = cmux_state::INIT;
|
||||
return true;
|
||||
}
|
||||
recover_ptr = static_cast<uint8_t *>(memchr(frame.ptr, SOF_MARKER, frame.len));
|
||||
if (recover_ptr && frame.len > recover_ptr - frame.ptr) {
|
||||
frame.len -= (recover_ptr - frame.ptr);
|
||||
frame.ptr = recover_ptr;
|
||||
state = cmux_state::INIT;
|
||||
ESP_LOGI("CMUX", "Protocol recovered");
|
||||
if (frame.len > 1 && frame.ptr[1] == SOF_MARKER) {
|
||||
// empty frame
|
||||
frame.advance();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// marker not found, continue with recovery
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CMux::on_header(CMuxFrame &frame)
|
||||
{
|
||||
if (frame.len > 0 && frame_header_offset == 1 && frame.ptr[0] == SOF_MARKER) {
|
||||
// Previously trailing SOF interpreted as heading SOF, remove it and restart HEADER
|
||||
frame.advance();
|
||||
return true;
|
||||
}
|
||||
if (frame.len + frame_header_offset < 4) {
|
||||
memcpy(frame_header + frame_header_offset, frame.ptr, frame.len);
|
||||
frame_header_offset += frame.len;
|
||||
return false; // need read more
|
||||
}
|
||||
size_t payload_offset = std::min(frame.len, 4 - frame_header_offset);
|
||||
memcpy(frame_header + frame_header_offset, frame.ptr, payload_offset);
|
||||
frame_header_offset += payload_offset;
|
||||
dlci = frame_header[1] >> 2;
|
||||
type = frame_header[2];
|
||||
payload_len = (frame_header[3] >> 1);
|
||||
frame.advance(payload_offset);
|
||||
state = cmux_state::PAYLOAD;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMux::on_payload(CMuxFrame &frame)
|
||||
{
|
||||
ESP_LOGD("CMUX", "Payload frame: dlci:%02x type:%02x payload:%d available:%d", dlci, type, payload_len, frame.len);
|
||||
if (frame.len < payload_len) { // payload
|
||||
state = cmux_state::PAYLOAD;
|
||||
data_available(frame.ptr, frame.len); // partial read
|
||||
payload_len -= frame.len;
|
||||
return false;
|
||||
} else { // complete
|
||||
if (payload_len > 0) {
|
||||
data_available(&frame.ptr[0], payload_len); // rest read
|
||||
}
|
||||
frame.advance((payload_len));
|
||||
state = cmux_state::FOOTER;
|
||||
payload_len = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMux::on_footer(CMuxFrame &frame)
|
||||
{
|
||||
size_t footer_offset = 0;
|
||||
if (frame.len + frame_header_offset < 6) {
|
||||
memcpy(frame_header + frame_header_offset, frame.ptr, frame.len);
|
||||
frame_header_offset += frame.len;
|
||||
return false; // need read more
|
||||
} else {
|
||||
footer_offset = std::min(frame.len, 6 - frame_header_offset);
|
||||
memcpy(frame_header + frame_header_offset, frame.ptr, footer_offset);
|
||||
if (frame_header[5] != SOF_MARKER) {
|
||||
ESP_LOGW("CMUX", "Protocol mismatch: Missed trailing SOF, recovering...");
|
||||
payload_start = nullptr;
|
||||
total_payload_size = 0;
|
||||
state = cmux_state::RECOVER;
|
||||
return true;
|
||||
}
|
||||
frame.advance(footer_offset);
|
||||
state = cmux_state::INIT;
|
||||
frame_header_offset = 0;
|
||||
data_available(nullptr, 0);
|
||||
payload_start = nullptr;
|
||||
total_payload_size = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMux::on_cmux(uint8_t *data, size_t actual_len)
|
||||
{
|
||||
if (!data) {
|
||||
@ -138,115 +259,35 @@ bool CMux::on_cmux(uint8_t *data, size_t actual_len)
|
||||
actual_len = term->read(data, buffer_size);
|
||||
#endif
|
||||
}
|
||||
ESP_LOG_BUFFER_HEXDUMP("CMUX Received", data, actual_len, ESP_LOG_DEBUG);
|
||||
uint8_t* frame = data;
|
||||
uint8_t* recover_ptr;
|
||||
auto available_len = actual_len;
|
||||
size_t payload_offset = 0;
|
||||
size_t footer_offset = 0;
|
||||
while (available_len > 0) {
|
||||
ESP_LOG_BUFFER_HEXDUMP("CMUX Received", data, actual_len, ESP_LOG_VERBOSE);
|
||||
CMuxFrame frame = { .ptr = data, .len = actual_len };
|
||||
while (frame.len > 0) {
|
||||
switch (state) {
|
||||
case cmux_state::RECOVER:
|
||||
if (frame[0] == SOF_MARKER) {
|
||||
// already init state
|
||||
state = cmux_state::INIT;
|
||||
break;
|
||||
}
|
||||
recover_ptr = static_cast<uint8_t*>(memchr(frame, SOF_MARKER, available_len));
|
||||
if (recover_ptr && available_len > recover_ptr - frame) {
|
||||
available_len -= (recover_ptr - frame);
|
||||
frame = recover_ptr;
|
||||
state = cmux_state::INIT;
|
||||
ESP_LOGI("CMUX", "Protocol recovered");
|
||||
if (available_len > 1 && frame[1] == SOF_MARKER) {
|
||||
// empty frame
|
||||
available_len -= 1;
|
||||
frame += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// marker not found, continue with recovery
|
||||
case cmux_state::RECOVER:
|
||||
if (!on_recovery(frame)) {
|
||||
return false;
|
||||
case cmux_state::INIT:
|
||||
if (frame[0] != SOF_MARKER) {
|
||||
ESP_LOGW("CMUX", "Protocol mismatch: Missed leading SOF, recovering...");
|
||||
state = cmux_state::RECOVER;
|
||||
break;
|
||||
}
|
||||
if (available_len > 1 && frame[1] == SOF_MARKER) {
|
||||
// empty frame
|
||||
available_len -= 1;
|
||||
frame += 1;
|
||||
break;
|
||||
}
|
||||
state = cmux_state::HEADER;
|
||||
available_len--;
|
||||
frame_header_offset = 1;
|
||||
frame++;
|
||||
break;
|
||||
case cmux_state::HEADER:
|
||||
if (available_len > 0 && frame_header_offset == 1 && frame[0] == SOF_MARKER) {
|
||||
// Previously trailing SOF interpreted as heading SOF, remove it and restart HEADER
|
||||
available_len--;
|
||||
frame++;
|
||||
break;
|
||||
}
|
||||
if (available_len + frame_header_offset < 4) {
|
||||
memcpy(frame_header + frame_header_offset, frame, available_len);
|
||||
frame_header_offset += available_len;
|
||||
return false; // need read more
|
||||
}
|
||||
payload_offset = std::min(available_len, 4 - frame_header_offset);
|
||||
memcpy(frame_header + frame_header_offset, frame, payload_offset);
|
||||
frame_header_offset += payload_offset;
|
||||
dlci = frame_header[1] >> 2;
|
||||
type = frame_header[2];
|
||||
payload_len = (frame_header[3] >> 1);
|
||||
frame += payload_offset;
|
||||
available_len -= payload_offset;
|
||||
state = cmux_state::PAYLOAD;
|
||||
break;
|
||||
case cmux_state::PAYLOAD:
|
||||
ESP_LOGD("CMUX", "Payload frame: dlci:%02x type:%02x payload:%d available:%d", dlci, type, payload_len, available_len);
|
||||
if (available_len < payload_len) { // payload
|
||||
state = cmux_state::PAYLOAD;
|
||||
data_available(frame, available_len); // partial read
|
||||
payload_len -= available_len;
|
||||
return false;
|
||||
} else { // complete
|
||||
if (payload_len > 0) {
|
||||
data_available(&frame[0], payload_len); // rest read
|
||||
}
|
||||
available_len -= payload_len;
|
||||
frame += payload_len;
|
||||
state = cmux_state::FOOTER;
|
||||
payload_len = 0;
|
||||
}
|
||||
break;
|
||||
case cmux_state::FOOTER:
|
||||
if (available_len + frame_header_offset < 6) {
|
||||
memcpy(frame_header + frame_header_offset, frame, available_len);
|
||||
frame_header_offset += available_len;
|
||||
return false; // need read more
|
||||
} else {
|
||||
footer_offset = std::min(available_len, 6 - frame_header_offset);
|
||||
memcpy(frame_header + frame_header_offset, frame, footer_offset);
|
||||
if (frame_header[5] != SOF_MARKER) {
|
||||
ESP_LOGW("CMUX", "Protocol mismatch: Missed trailing SOF, recovering...");
|
||||
payload_start = nullptr;
|
||||
total_payload_size = 0;
|
||||
state = cmux_state::RECOVER;
|
||||
break;
|
||||
}
|
||||
frame += footer_offset;
|
||||
available_len -= footer_offset;
|
||||
state = cmux_state::INIT;
|
||||
frame_header_offset = 0;
|
||||
data_available(nullptr, 0);
|
||||
payload_start = nullptr;
|
||||
total_payload_size = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case cmux_state::INIT:
|
||||
if (!on_init(frame)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case cmux_state::HEADER:
|
||||
if (!on_header(frame)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case cmux_state::PAYLOAD:
|
||||
if (!on_payload(frame)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case cmux_state::FOOTER:
|
||||
if (!on_footer(frame)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -262,8 +303,7 @@ bool CMux::init()
|
||||
});
|
||||
|
||||
sabm_ack = -1;
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
{
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
int timeout = 0;
|
||||
send_sabm(i);
|
||||
while (true) {
|
||||
@ -273,8 +313,9 @@ bool CMux::init()
|
||||
sabm_ack = -1;
|
||||
break;
|
||||
}
|
||||
if (timeout++ > 100)
|
||||
if (timeout++ > 100) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -288,8 +329,9 @@ int CMux::write(int virtual_term, uint8_t *data, size_t len)
|
||||
size_t need_write = len;
|
||||
while (need_write > 0) {
|
||||
size_t batch_len = need_write;
|
||||
if (batch_len > cmux_max_len)
|
||||
if (batch_len > cmux_max_len) {
|
||||
batch_len = cmux_max_len;
|
||||
}
|
||||
uint8_t frame[6];
|
||||
frame[0] = SOF_MARKER;
|
||||
frame[1] = (i << 2) + 1;
|
||||
@ -303,14 +345,16 @@ int CMux::write(int virtual_term, uint8_t *data, size_t len)
|
||||
term->write(frame + 4, 2);
|
||||
ESP_LOG_BUFFER_HEXDUMP("Send", frame, 4, ESP_LOG_VERBOSE);
|
||||
ESP_LOG_BUFFER_HEXDUMP("Send", data, batch_len, ESP_LOG_VERBOSE);
|
||||
ESP_LOG_BUFFER_HEXDUMP("Send", frame+4, 2, ESP_LOG_VERBOSE);
|
||||
ESP_LOG_BUFFER_HEXDUMP("Send", frame + 4, 2, ESP_LOG_VERBOSE);
|
||||
need_write -= batch_len;
|
||||
data += batch_len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void CMux::set_read_cb(int inst, std::function<bool(uint8_t *, size_t)> f) {
|
||||
if (inst < max_terms)
|
||||
void CMux::set_read_cb(int inst, std::function<bool(uint8_t *, size_t)> f)
|
||||
{
|
||||
if (inst < MAX_TERMINALS_NUM) {
|
||||
read_cb[inst] = std::move(f);
|
||||
}
|
||||
}
|
||||
|
@ -23,49 +23,53 @@ namespace esp_modem::dce_commands {
|
||||
|
||||
static const char *TAG = "command_lib";
|
||||
|
||||
command_result generic_command(CommandableIf* t, const std::string &command,
|
||||
const std::list<std::string_view>& pass_phrase,
|
||||
const std::list<std::string_view>& fail_phrase,
|
||||
uint32_t timeout_ms)
|
||||
command_result generic_command(CommandableIf *t, const std::string &command,
|
||||
const std::list<std::string_view> &pass_phrase,
|
||||
const std::list<std::string_view> &fail_phrase,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s command %s\n", __func__, command.c_str());
|
||||
return t->command(command, [&](uint8_t *data, size_t len) {
|
||||
std::string_view response((char*)data, len);
|
||||
if (data == nullptr || len == 0 || response.empty())
|
||||
std::string_view response((char *)data, len);
|
||||
if (data == nullptr || len == 0 || response.empty()) {
|
||||
return command_result::TIMEOUT;
|
||||
}
|
||||
ESP_LOGD(TAG, "Response: %.*s\n", (int)response.length(), response.data());
|
||||
for (auto &it : pass_phrase)
|
||||
if (response.find(it) != std::string::npos)
|
||||
if (response.find(it) != std::string::npos) {
|
||||
return command_result::OK;
|
||||
}
|
||||
for (auto &it : fail_phrase)
|
||||
if (response.find(it) != std::string::npos)
|
||||
if (response.find(it) != std::string::npos) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
return command_result::TIMEOUT;
|
||||
}, timeout_ms);
|
||||
|
||||
}
|
||||
|
||||
static inline command_result generic_command(CommandableIf* t, const std::string& command,
|
||||
const std::string& pass_phrase,
|
||||
const std::string& fail_phrase, uint32_t timeout_ms)
|
||||
static inline command_result generic_command(CommandableIf *t, const std::string &command,
|
||||
const std::string &pass_phrase,
|
||||
const std::string &fail_phrase, uint32_t timeout_ms)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
const auto pass = std::list<std::string_view>({pass_phrase});
|
||||
const auto fail = std::list<std::string_view>({fail_phrase});
|
||||
return generic_command(t, command, pass, fail, timeout_ms);
|
||||
}
|
||||
|
||||
static inline command_result generic_get_string(CommandableIf* t, const std::string& command, std::string_view& output, uint32_t timeout_ms = 500)
|
||||
static inline command_result generic_get_string(CommandableIf *t, const std::string &command, std::string_view &output, uint32_t timeout_ms = 500)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return t->command(command, [&](uint8_t *data, size_t len) {
|
||||
size_t pos = 0;
|
||||
std::string_view response((char*)data, len);
|
||||
std::string_view response((char *)data, len);
|
||||
while ((pos = response.find('\n')) != std::string::npos) {
|
||||
std::string_view token = response.substr(0, pos);
|
||||
for (auto it = token.end() - 1; it > token.begin(); it--) // strip trailing CR or LF
|
||||
if (*it == '\r' || *it == '\n')
|
||||
if (*it == '\r' || *it == '\n') {
|
||||
token.remove_suffix(1);
|
||||
}
|
||||
ESP_LOGV(TAG, "Token: {%.*s}\n", static_cast<int>(token.size()), token.data());
|
||||
|
||||
if (token.find("OK") != std::string::npos) {
|
||||
@ -75,147 +79,157 @@ static inline command_result generic_get_string(CommandableIf* t, const std::str
|
||||
} else if (token.size() > 2) {
|
||||
output = token;
|
||||
}
|
||||
response = response.substr(pos+1);
|
||||
response = response.substr(pos + 1);
|
||||
}
|
||||
return command_result::TIMEOUT;
|
||||
}, timeout_ms);
|
||||
}
|
||||
|
||||
static inline command_result generic_get_string(CommandableIf* t, const std::string& command, std::string& output, uint32_t timeout_ms = 500)
|
||||
static inline command_result generic_get_string(CommandableIf *t, const std::string &command, std::string &output, uint32_t timeout_ms = 500)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
auto ret = generic_get_string(t, command, out, timeout_ms);
|
||||
if (ret == command_result::OK)
|
||||
if (ret == command_result::OK) {
|
||||
output = out;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static inline command_result generic_command_common(CommandableIf* t, const std::string &command, uint32_t timeout = 500)
|
||||
static inline command_result generic_command_common(CommandableIf *t, const std::string &command, uint32_t timeout = 500)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command(t, command, "OK", "ERROR", timeout);
|
||||
}
|
||||
|
||||
command_result sync(CommandableIf* t)
|
||||
command_result sync(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT\r");
|
||||
}
|
||||
|
||||
command_result store_profile(CommandableIf* t)
|
||||
command_result store_profile(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT&W\r");
|
||||
}
|
||||
|
||||
command_result power_down(CommandableIf* t)
|
||||
command_result power_down(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command(t, "AT+QPOWD=1\r", "POWERED DOWN", "ERROR", 1000);
|
||||
}
|
||||
|
||||
command_result power_down_sim7xxx(CommandableIf* t)
|
||||
command_result power_down_sim7xxx(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT+CPOF\r", 1000);
|
||||
}
|
||||
|
||||
command_result power_down_sim8xx(CommandableIf* t)
|
||||
command_result power_down_sim8xx(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command(t, "AT+CPOWD=1\r", "POWER DOWN", "ERROR", 1000);
|
||||
}
|
||||
|
||||
command_result reset(CommandableIf* t)
|
||||
command_result reset(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command(t, "AT+CRESET\r", "PB DONE", "ERROR", 60000);
|
||||
}
|
||||
|
||||
command_result set_baud(CommandableIf* t, int baud)
|
||||
command_result set_baud(CommandableIf *t, int baud)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT+IPR=" + std::to_string(baud) + "\r");
|
||||
}
|
||||
|
||||
command_result hang_up(CommandableIf* t)
|
||||
command_result hang_up(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "ATH\r", 90000);
|
||||
}
|
||||
|
||||
command_result get_battery_status(CommandableIf* t, int& voltage, int &bcs, int &bcl)
|
||||
command_result get_battery_status(CommandableIf *t, int &voltage, int &bcs, int &bcl)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
auto ret = generic_get_string(t, "AT+CBC\r", out);
|
||||
if (ret != command_result::OK)
|
||||
if (ret != command_result::OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr std::string_view pattern = "+CBC: ";
|
||||
if (out.find(pattern) == std::string_view::npos)
|
||||
if (out.find(pattern) == std::string_view::npos) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
// Parsing +CBC: <bcs>,<bcl>,<voltage>
|
||||
out = out.substr(pattern.size());
|
||||
int pos, value, property = 0;
|
||||
while ((pos = out.find(',') != std::string::npos)) {
|
||||
if (std::from_chars(out.data(), out.data() + pos, value).ec == std::errc::invalid_argument)
|
||||
while ((pos = out.find(',')) != std::string::npos) {
|
||||
if (std::from_chars(out.data(), out.data() + pos, value).ec == std::errc::invalid_argument) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
switch (property++) {
|
||||
case 0: bcs = value;
|
||||
break;
|
||||
case 1: bcl = value;
|
||||
break;
|
||||
default:
|
||||
return command_result::FAIL;
|
||||
case 0: bcs = value;
|
||||
break;
|
||||
case 1: bcl = value;
|
||||
break;
|
||||
default:
|
||||
return command_result::FAIL;
|
||||
}
|
||||
out = out.substr(pos + 1);
|
||||
}
|
||||
if (std::from_chars(out.data(), out.data() + out.size(), voltage).ec == std::errc::invalid_argument)
|
||||
if (std::from_chars(out.data(), out.data() + out.size(), voltage).ec == std::errc::invalid_argument) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
return command_result::OK;
|
||||
}
|
||||
|
||||
command_result get_battery_status_sim7xxx(CommandableIf* t, int& voltage, int &bcs, int &bcl)
|
||||
command_result get_battery_status_sim7xxx(CommandableIf *t, int &voltage, int &bcs, int &bcl)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
auto ret = generic_get_string(t, "AT+CBC\r", out);
|
||||
if (ret != command_result::OK)
|
||||
if (ret != command_result::OK) {
|
||||
return ret;
|
||||
}
|
||||
// Parsing +CBC: <voltage in Volts> V
|
||||
constexpr std::string_view pattern = "+CBC: ";
|
||||
constexpr int num_pos = pattern.size();
|
||||
int dot_pos;
|
||||
if (out.find(pattern) == std::string::npos ||
|
||||
(dot_pos = out.find('.')) == std::string::npos)
|
||||
(dot_pos = out.find('.')) == std::string::npos) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
|
||||
int volt, fraction;
|
||||
if (std::from_chars(out.data() + num_pos, out.data() + dot_pos, volt).ec == std::errc::invalid_argument)
|
||||
if (std::from_chars(out.data() + num_pos, out.data() + dot_pos, volt).ec == std::errc::invalid_argument) {
|
||||
return command_result::FAIL;
|
||||
if (std::from_chars(out.data() + dot_pos + 1, out.data() + out.size() - 1, fraction).ec == std::errc::invalid_argument)
|
||||
}
|
||||
if (std::from_chars(out.data() + dot_pos + 1, out.data() + out.size() - 1, fraction).ec == std::errc::invalid_argument) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
bcl = bcs = -1; // not available for these models
|
||||
voltage = 1000*volt + fraction;
|
||||
voltage = 1000 * volt + fraction;
|
||||
return command_result::OK;
|
||||
}
|
||||
|
||||
command_result set_flow_control(CommandableIf* t, int dce_flow, int dte_flow)
|
||||
command_result set_flow_control(CommandableIf *t, int dce_flow, int dte_flow)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
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)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
auto ret = generic_get_string(t, "AT+COPS?\r", out, 75000);
|
||||
if (ret != command_result::OK)
|
||||
if (ret != command_result::OK) {
|
||||
return ret;
|
||||
}
|
||||
auto pos = out.find("+COPS");
|
||||
auto property = 0;
|
||||
while (pos != std::string::npos) {
|
||||
@ -229,113 +243,118 @@ command_result get_operator_name(CommandableIf* t, std::string& operator_name)
|
||||
return command_result::FAIL;
|
||||
}
|
||||
|
||||
command_result set_echo(CommandableIf* t, bool on)
|
||||
command_result set_echo(CommandableIf *t, bool on)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
if (on)
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
if (on) {
|
||||
return generic_command_common(t, "ATE1\r");
|
||||
}
|
||||
return generic_command_common(t, "ATE0\r");
|
||||
}
|
||||
|
||||
command_result set_pdp_context(CommandableIf* t, PdpContext& pdp)
|
||||
command_result set_pdp_context(CommandableIf *t, PdpContext &pdp)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string pdp_command = "AT+CGDCONT=" + std::to_string(pdp.context_id) +
|
||||
",\"" + pdp.protocol_type + "\",\"" + pdp.apn + "\"\r";
|
||||
return generic_command_common(t, pdp_command);
|
||||
}
|
||||
|
||||
command_result set_data_mode(CommandableIf* t)
|
||||
command_result set_data_mode(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
|
||||
}
|
||||
|
||||
command_result set_data_mode_sim8xx(CommandableIf* t)
|
||||
command_result set_data_mode_sim8xx(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command(t, "ATD*99##\r", "CONNECT", "ERROR", 5000);
|
||||
}
|
||||
|
||||
command_result resume_data_mode(CommandableIf* t)
|
||||
command_result resume_data_mode(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command(t, "ATO\r", "CONNECT", "ERROR", 5000);
|
||||
}
|
||||
|
||||
command_result set_command_mode(CommandableIf* t)
|
||||
command_result set_command_mode(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
const auto pass = std::list<std::string_view>({"NO CARRIER", "OK"});
|
||||
const auto fail = std::list<std::string_view>({"ERROR"});
|
||||
return generic_command(t, "+++", pass, fail, 5000);
|
||||
}
|
||||
|
||||
command_result get_imsi(CommandableIf* t, std::string& imsi_number)
|
||||
command_result get_imsi(CommandableIf *t, std::string &imsi_number)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_get_string(t, "AT+CIMI\r", imsi_number, 5000);
|
||||
}
|
||||
|
||||
command_result get_imei(CommandableIf* t, std::string& out)
|
||||
command_result get_imei(CommandableIf *t, std::string &out)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_get_string(t, "AT+CGSN\r", out, 5000);
|
||||
}
|
||||
|
||||
command_result get_module_name(CommandableIf* t, std::string& out)
|
||||
command_result get_module_name(CommandableIf *t, std::string &out)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_get_string(t, "AT+CGMM\r", out, 5000);
|
||||
}
|
||||
|
||||
command_result sms_txt_mode(CommandableIf* t, bool txt = true)
|
||||
command_result sms_txt_mode(CommandableIf *t, bool txt = true)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
if (txt)
|
||||
return generic_command_common(t, "AT+CMGF=1\r"); // Text mode (default)
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
if (txt) {
|
||||
return generic_command_common(t, "AT+CMGF=1\r"); // Text mode (default)
|
||||
}
|
||||
return generic_command_common(t, "AT+CMGF=0\r"); // PDU mode
|
||||
}
|
||||
|
||||
command_result sms_character_set(CommandableIf* t)
|
||||
command_result sms_character_set(CommandableIf *t)
|
||||
{
|
||||
// Sets the default GSM character set
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT+CSCS=\"GSM\"\r");
|
||||
}
|
||||
|
||||
command_result send_sms(CommandableIf* t, const std::string& number, const std::string& message)
|
||||
command_result send_sms(CommandableIf *t, const std::string &number, const std::string &message)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
auto ret = t->command("AT+CMGS=\"" + number + "\"\r", [&](uint8_t *data, size_t len) {
|
||||
std::string_view response((char*)data, len);
|
||||
ESP_LOGD(TAG,"Send SMS response %.*s", static_cast<int>(response.size()), response.data());
|
||||
std::string_view response((char *)data, len);
|
||||
ESP_LOGD(TAG, "Send SMS response %.*s", static_cast<int>(response.size()), response.data());
|
||||
if (response.find('>') != std::string::npos) {
|
||||
return command_result::OK;
|
||||
}
|
||||
return command_result::TIMEOUT;
|
||||
}, 5000, ' ');
|
||||
if (ret != command_result::OK)
|
||||
if (ret != command_result::OK) {
|
||||
return ret;
|
||||
return generic_command_common(t, message +"\x1A", 120000);
|
||||
}
|
||||
return generic_command_common(t, message + "\x1A", 120000);
|
||||
}
|
||||
|
||||
|
||||
command_result set_cmux(CommandableIf* t)
|
||||
command_result set_cmux(CommandableIf *t)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
return generic_command_common(t, "AT+CMUX=0\r");
|
||||
}
|
||||
|
||||
command_result read_pin(CommandableIf* t, bool& pin_ok)
|
||||
command_result read_pin(CommandableIf *t, bool &pin_ok)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
auto ret = generic_get_string(t, "AT+CPIN?\r", out);
|
||||
if (ret != command_result::OK)
|
||||
if (ret != command_result::OK) {
|
||||
return ret;
|
||||
if (out.find("+CPIN:") == std::string::npos)
|
||||
}
|
||||
if (out.find("+CPIN:") == std::string::npos) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
if (out.find("SIM PIN") != std::string::npos || out.find("SIM PUK") != std::string::npos) {
|
||||
pin_ok = false;
|
||||
return command_result::OK;
|
||||
@ -347,32 +366,36 @@ command_result read_pin(CommandableIf* t, bool& pin_ok)
|
||||
return command_result::FAIL; // Neither pin-ok, nor waiting for pin/puk -> mark as error
|
||||
}
|
||||
|
||||
command_result set_pin(CommandableIf* t, const std::string& pin)
|
||||
command_result set_pin(CommandableIf *t, const std::string &pin)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string set_pin_command = "AT+CPIN=" + pin + "\r";
|
||||
return generic_command_common(t, set_pin_command);
|
||||
}
|
||||
|
||||
command_result get_signal_quality(CommandableIf* t, int &rssi, int &ber)
|
||||
command_result get_signal_quality(CommandableIf *t, int &rssi, int &ber)
|
||||
{
|
||||
ESP_LOGV(TAG,"%s", __func__ );
|
||||
ESP_LOGV(TAG, "%s", __func__ );
|
||||
std::string_view out;
|
||||
auto ret = generic_get_string(t, "AT+CSQ\r", out);
|
||||
if (ret != command_result::OK)
|
||||
if (ret != command_result::OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr std::string_view pattern = "+CSQ: ";
|
||||
constexpr int rssi_pos = pattern.size();
|
||||
int ber_pos;
|
||||
if (out.find(pattern) == std::string::npos ||
|
||||
(ber_pos = out.find(',')) == std::string::npos)
|
||||
(ber_pos = out.find(',')) == std::string::npos) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
|
||||
if (std::from_chars(out.data() + rssi_pos, out.data() + ber_pos, rssi).ec == std::errc::invalid_argument)
|
||||
if (std::from_chars(out.data() + rssi_pos, out.data() + ber_pos, rssi).ec == std::errc::invalid_argument) {
|
||||
return command_result::FAIL;
|
||||
if (std::from_chars(out.data() + ber_pos + 1, out.data() + out.size(), ber).ec == std::errc::invalid_argument)
|
||||
}
|
||||
if (std::from_chars(out.data() + ber_pos + 1, out.data() + out.size(), ber).ec == std::errc::invalid_argument) {
|
||||
return command_result::FAIL;
|
||||
}
|
||||
return command_result::OK;
|
||||
}
|
||||
|
||||
|
@ -22,44 +22,53 @@ namespace esp_modem {
|
||||
bool DCE_Mode::set(DTE *dte, ModuleIf *device, Netif &netif, modem_mode m)
|
||||
{
|
||||
switch (m) {
|
||||
case modem_mode::UNDEF:
|
||||
break;
|
||||
case modem_mode::COMMAND_MODE:
|
||||
if (mode == modem_mode::COMMAND_MODE)
|
||||
return false;
|
||||
netif.stop();
|
||||
if (!device->set_mode(modem_mode::COMMAND_MODE))
|
||||
return false;
|
||||
dte->set_read_cb([&](uint8_t *data, size_t len) -> bool {
|
||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_INFO);
|
||||
return false;
|
||||
});
|
||||
netif.wait_until_ppp_exits();
|
||||
dte->set_read_cb(nullptr);
|
||||
if (!dte->set_mode(modem_mode::COMMAND_MODE))
|
||||
return false;
|
||||
mode = m;
|
||||
return true;
|
||||
case modem_mode::DATA_MODE:
|
||||
if (mode == modem_mode::DATA_MODE)
|
||||
return false;
|
||||
if (!device->setup_data_mode())
|
||||
return false;
|
||||
if (!device->set_mode(modem_mode::DATA_MODE))
|
||||
return false;
|
||||
if (!dte->set_mode(modem_mode::DATA_MODE))
|
||||
return false;
|
||||
netif.start();
|
||||
mode = m;
|
||||
return true;
|
||||
case modem_mode::CMUX_MODE:
|
||||
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE)
|
||||
return false;
|
||||
device->set_mode(modem_mode::CMUX_MODE);
|
||||
if (!dte->set_mode(modem_mode::CMUX_MODE))
|
||||
return false;
|
||||
mode = modem_mode::COMMAND_MODE;
|
||||
return true;
|
||||
case modem_mode::UNDEF:
|
||||
break;
|
||||
case modem_mode::COMMAND_MODE:
|
||||
if (mode == modem_mode::COMMAND_MODE) {
|
||||
return false;
|
||||
}
|
||||
netif.stop();
|
||||
if (!device->set_mode(modem_mode::COMMAND_MODE)) {
|
||||
return false;
|
||||
}
|
||||
dte->set_read_cb([&](uint8_t *data, size_t len) -> bool {
|
||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data", data, len, ESP_LOG_INFO);
|
||||
return false;
|
||||
});
|
||||
netif.wait_until_ppp_exits();
|
||||
dte->set_read_cb(nullptr);
|
||||
if (!dte->set_mode(modem_mode::COMMAND_MODE)) {
|
||||
return false;
|
||||
}
|
||||
mode = m;
|
||||
return true;
|
||||
case modem_mode::DATA_MODE:
|
||||
if (mode == modem_mode::DATA_MODE) {
|
||||
return false;
|
||||
}
|
||||
if (!device->setup_data_mode()) {
|
||||
return false;
|
||||
}
|
||||
if (!device->set_mode(modem_mode::DATA_MODE)) {
|
||||
return false;
|
||||
}
|
||||
if (!dte->set_mode(modem_mode::DATA_MODE)) {
|
||||
return false;
|
||||
}
|
||||
netif.start();
|
||||
mode = m;
|
||||
return true;
|
||||
case modem_mode::CMUX_MODE:
|
||||
if (mode == modem_mode::DATA_MODE || mode == modem_mode::CMUX_MODE) {
|
||||
return false;
|
||||
}
|
||||
device->set_mode(modem_mode::CMUX_MODE);
|
||||
if (!dte->set_mode(modem_mode::CMUX_MODE)) {
|
||||
return false;
|
||||
}
|
||||
mode = modem_mode::COMMAND_MODE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -22,10 +22,10 @@ using namespace esp_modem;
|
||||
static const size_t dte_default_buffer_size = 1000;
|
||||
|
||||
DTE::DTE(const esp_modem_dte_config *config, std::unique_ptr<Terminal> terminal):
|
||||
buffer_size(config->dte_buffer_size), consumed(0),
|
||||
buffer(std::make_unique<uint8_t[]>(buffer_size)),
|
||||
term(std::move(terminal)), command_term(term.get()), other_term(nullptr),
|
||||
mode(modem_mode::UNDEF) {}
|
||||
buffer_size(config->dte_buffer_size), consumed(0),
|
||||
buffer(std::make_unique<uint8_t[]>(buffer_size)),
|
||||
term(std::move(terminal)), command_term(term.get()), other_term(nullptr),
|
||||
mode(modem_mode::UNDEF) {}
|
||||
|
||||
DTE::DTE(std::unique_ptr<Terminal> terminal):
|
||||
buffer_size(dte_default_buffer_size), consumed(0),
|
||||
@ -72,17 +72,21 @@ command_result DTE::command(const std::string &cmd, got_line_cb got_line, uint32
|
||||
bool DTE::setup_cmux()
|
||||
{
|
||||
auto original_term = std::move(term);
|
||||
if (original_term == nullptr)
|
||||
if (original_term == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto cmux_term = std::make_shared<CMux>(std::move(original_term), std::move(buffer), buffer_size);
|
||||
if (cmux_term == nullptr)
|
||||
if (cmux_term == nullptr) {
|
||||
return false;
|
||||
}
|
||||
buffer_size = 0;
|
||||
if (!cmux_term->init())
|
||||
if (!cmux_term->init()) {
|
||||
return false;
|
||||
}
|
||||
term = std::make_unique<CMuxInstance>(cmux_term, 0);
|
||||
if (term == nullptr)
|
||||
if (term == nullptr) {
|
||||
return false;
|
||||
}
|
||||
command_term = term.get(); // use command terminal as previously
|
||||
other_term = std::make_unique<CMuxInstance>(cmux_term, 1);
|
||||
return true;
|
||||
@ -110,8 +114,9 @@ void DTE::set_read_cb(std::function<bool(uint8_t *, size_t)> f)
|
||||
data = buffer.get();
|
||||
len = term->read(buffer.get(), buffer_size);
|
||||
}
|
||||
if (on_data)
|
||||
if (on_data) {
|
||||
return on_data(data, len);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
@ -20,18 +20,18 @@
|
||||
namespace esp_modem {
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<T> create_device(const std::shared_ptr<DTE>& dte, std::string &apn)
|
||||
std::shared_ptr<T> create_device(const std::shared_ptr<DTE> &dte, std::string &apn)
|
||||
{
|
||||
auto pdp = std::make_unique<PdpContext>(apn);
|
||||
return std::make_shared<T>(dte, std::move(pdp));
|
||||
}
|
||||
|
||||
std::shared_ptr<GenericModule> create_generic_module(const std::shared_ptr<DTE>& dte, std::string &apn)
|
||||
std::shared_ptr<GenericModule> create_generic_module(const std::shared_ptr<DTE> &dte, std::string &apn)
|
||||
{
|
||||
return create_device<GenericModule>(dte, apn);
|
||||
}
|
||||
|
||||
std::shared_ptr<SIM7600> create_SIM7600_module(const std::shared_ptr<DTE>& dte, std::string &apn)
|
||||
std::shared_ptr<SIM7600> create_SIM7600_module(const std::shared_ptr<DTE> &dte, std::string &apn)
|
||||
{
|
||||
return create_device<SIM7600>(dte, apn);
|
||||
}
|
||||
@ -42,7 +42,8 @@ std::shared_ptr<SIM7600> create_SIM7600_module(const std::shared_ptr<DTE>& dte,
|
||||
#include "cxx_include/esp_modem_dce_factory.hpp"
|
||||
|
||||
namespace esp_modem::dce_factory {
|
||||
std::unique_ptr<PdpContext> FactoryHelper::create_pdp_context(std::string &apn) {
|
||||
std::unique_ptr<PdpContext> FactoryHelper::create_pdp_context(std::string &apn)
|
||||
{
|
||||
return std::unique_ptr<PdpContext>();
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
namespace esp_modem {
|
||||
|
||||
GenericModule::GenericModule(std::shared_ptr<DTE> dte, const dce_config *config) :
|
||||
dte(std::move(dte)), pdp(std::make_unique<PdpContext>(config->apn)) {}
|
||||
dte(std::move(dte)), pdp(std::make_unique<PdpContext>(config->apn)) {}
|
||||
|
||||
//
|
||||
// Define preprocessor's forwarding to dce_commands definitions
|
||||
@ -27,9 +27,13 @@ GenericModule::GenericModule(std::shared_ptr<DTE> dte, const dce_config *config)
|
||||
|
||||
// Helper macros to handle multiple arguments of declared API
|
||||
#define ARGS0
|
||||
#define ARGS1 , x
|
||||
#define ARGS2 , x , y
|
||||
#define ARGS3 , x , y , z
|
||||
#define ARGS1 , p1
|
||||
#define ARGS2 , p1 , p2
|
||||
#define ARGS3 , p1 , p2 , p3
|
||||
#define ARGS4 , p1 , p2 , p3, p4
|
||||
#define ARGS5 , p1 , p2 , p3, p4, p5
|
||||
#define ARGS6 , p1 , p2 , p3, p4, p5, p6
|
||||
|
||||
#define _ARGS(x) ARGS ## x
|
||||
#define ARGS(x) _ARGS(x)
|
||||
|
||||
@ -46,35 +50,24 @@ DECLARE_ALL_COMMAND_APIS(return_type name(...) )
|
||||
//
|
||||
// Handle specific commands for specific supported modems
|
||||
//
|
||||
command_result SIM7600::get_module_name(std::string &name) {
|
||||
name = "7600";
|
||||
return command_result::OK;
|
||||
}
|
||||
|
||||
command_result SIM7600::get_battery_status(int& voltage, int &bcs, int &bcl) {
|
||||
command_result SIM7600::get_battery_status(int &voltage, int &bcs, int &bcl)
|
||||
{
|
||||
return dce_commands::get_battery_status_sim7xxx(dte.get(), voltage, bcs, bcl);
|
||||
}
|
||||
|
||||
command_result SIM7600::power_down() {
|
||||
command_result SIM7600::power_down()
|
||||
{
|
||||
return dce_commands::power_down_sim7xxx(dte.get());
|
||||
}
|
||||
|
||||
command_result SIM800::get_module_name(std::string &name) {
|
||||
name = "800L";
|
||||
return command_result::OK;
|
||||
}
|
||||
|
||||
command_result SIM800::power_down() {
|
||||
command_result SIM800::power_down()
|
||||
{
|
||||
return dce_commands::power_down_sim8xx(dte.get());
|
||||
}
|
||||
|
||||
command_result SIM800::set_data_mode() {
|
||||
command_result SIM800::set_data_mode()
|
||||
{
|
||||
return dce_commands::set_data_mode_sim8xx(dte.get());
|
||||
}
|
||||
|
||||
command_result BG96::get_module_name(std::string &name) {
|
||||
name = "BG96";
|
||||
return command_result::OK;
|
||||
}
|
||||
|
||||
}
|
@ -24,7 +24,8 @@
|
||||
namespace esp_modem {
|
||||
|
||||
void Netif::on_ppp_changed(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
auto *ppp = static_cast<Netif *>(arg);
|
||||
if (event_id < NETIF_PP_PHASE_OFFSET) {
|
||||
ESP_LOGI("esp_modem_netif", "PPP state changed event %d", event_id);
|
||||
@ -33,7 +34,8 @@ void Netif::on_ppp_changed(void *arg, esp_event_base_t event_base,
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t Netif::esp_modem_dte_transmit(void *h, void *buffer, size_t len) {
|
||||
esp_err_t Netif::esp_modem_dte_transmit(void *h, void *buffer, size_t len)
|
||||
{
|
||||
auto *ppp = static_cast<Netif *>(h);
|
||||
if (ppp->signal.is_any(PPP_STARTED)) {
|
||||
if (ppp->ppp_dte && ppp->ppp_dte->write((uint8_t *) buffer, len) > 0) {
|
||||
@ -43,7 +45,8 @@ esp_err_t Netif::esp_modem_dte_transmit(void *h, void *buffer, size_t len) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args) {
|
||||
esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args)
|
||||
{
|
||||
auto d = (ppp_netif_driver *) args;
|
||||
esp_netif_driver_ifconfig_t driver_ifconfig = {};
|
||||
driver_ifconfig.transmit = Netif::esp_modem_dte_transmit;
|
||||
@ -53,7 +56,8 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args) {
|
||||
// check if PPP error events are enabled, if not, do enable the error occurred/state changed
|
||||
// to notify the modem layer when switching modes
|
||||
esp_netif_ppp_config_t ppp_config = { .ppp_phase_event_enabled = true, // assuming phase enabled, as earlier IDFs
|
||||
.ppp_error_event_enabled = false }; // don't provide cfg getters so we enable both events
|
||||
.ppp_error_event_enabled = false
|
||||
}; // don't provide cfg getters so we enable both events
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 4
|
||||
esp_netif_ppp_get_params(esp_netif, &ppp_config);
|
||||
#endif // ESP-IDF >= v4.4
|
||||
@ -65,25 +69,28 @@ esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void Netif::receive(uint8_t *data, size_t len) {
|
||||
void Netif::receive(uint8_t *data, size_t len)
|
||||
{
|
||||
if (signal.is_any(PPP_STARTED)) {
|
||||
esp_netif_receive(driver.base.netif, data, len, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
|
||||
ppp_dte(std::move(e)), netif(ppp_netif) {
|
||||
ppp_dte(std::move(e)), netif(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_event_handler_register(IP_EVENT, IP_EVENT_PPP_LOST_IP, esp_netif_action_disconnected, ppp_netif));
|
||||
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));
|
||||
}
|
||||
|
||||
void Netif::start() {
|
||||
void Netif::start()
|
||||
{
|
||||
ppp_dte->set_read_cb([this](uint8_t *data, size_t len) -> bool {
|
||||
receive(data, len);
|
||||
return false;
|
||||
@ -92,12 +99,14 @@ void Netif::start() {
|
||||
signal.set(PPP_STARTED);
|
||||
}
|
||||
|
||||
void Netif::stop() {
|
||||
void Netif::stop()
|
||||
{
|
||||
esp_netif_action_stop(driver.base.netif, nullptr, 0, nullptr);
|
||||
signal.clear(PPP_STARTED);
|
||||
}
|
||||
|
||||
Netif::~Netif() {
|
||||
Netif::~Netif()
|
||||
{
|
||||
if (signal.is_any(PPP_STARTED)) {
|
||||
esp_netif_action_stop(driver.base.netif, nullptr, 0, nullptr);
|
||||
signal.clear(PPP_STARTED);
|
||||
@ -108,7 +117,8 @@ Netif::~Netif() {
|
||||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_PPP_LOST_IP, esp_netif_action_disconnected);
|
||||
}
|
||||
|
||||
void Netif::wait_until_ppp_exits() {
|
||||
void Netif::wait_until_ppp_exits()
|
||||
{
|
||||
signal.wait(PPP_EXIT, 30000);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,8 @@
|
||||
namespace esp_modem {
|
||||
|
||||
void Netif::on_ppp_changed(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t Netif::esp_modem_dte_transmit(void *h, void *buffer, size_t len)
|
||||
@ -29,7 +30,8 @@ esp_err_t Netif::esp_modem_dte_transmit(void *h, void *buffer, size_t len)
|
||||
return len;
|
||||
}
|
||||
|
||||
esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args) {
|
||||
esp_err_t Netif::esp_modem_post_attach(esp_netif_t *esp_netif, void *args)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -39,7 +41,7 @@ void Netif::receive(uint8_t *data, size_t len)
|
||||
}
|
||||
|
||||
Netif::Netif(std::shared_ptr<DTE> e, esp_netif_t *ppp_netif) :
|
||||
ppp_dte(std::move(e)), netif(ppp_netif) {}
|
||||
ppp_dte(std::move(e)), netif(ppp_netif) {}
|
||||
|
||||
void Netif::start()
|
||||
{
|
||||
@ -48,7 +50,7 @@ void Netif::start()
|
||||
return false;
|
||||
});
|
||||
netif->transmit = esp_modem_dte_transmit;
|
||||
netif->ctx = (void*)this;
|
||||
netif->ctx = (void *)this;
|
||||
signal.set(PPP_STARTED);
|
||||
}
|
||||
|
||||
@ -56,7 +58,8 @@ void Netif::stop() {}
|
||||
|
||||
Netif::~Netif() = default;
|
||||
|
||||
void Netif::wait_until_ppp_exits() {
|
||||
void Netif::wait_until_ppp_exits()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
void Lock::unlock() {
|
||||
void Lock::unlock()
|
||||
{
|
||||
xSemaphoreGiveRecursive(m);
|
||||
}
|
||||
|
||||
@ -30,11 +31,13 @@ Lock::Lock(): m(nullptr)
|
||||
throw_if_false(m != nullptr, "create signal event group failed");
|
||||
}
|
||||
|
||||
Lock::~Lock() {
|
||||
Lock::~Lock()
|
||||
{
|
||||
vSemaphoreDelete(m);
|
||||
}
|
||||
|
||||
void Lock::lock() {
|
||||
void Lock::lock()
|
||||
{
|
||||
xSemaphoreTakeRecursive(m, portMAX_DELAY);
|
||||
}
|
||||
|
||||
@ -74,12 +77,13 @@ bool SignalGroup::wait_any(uint32_t flags, uint32_t time_ms)
|
||||
|
||||
SignalGroup::~SignalGroup()
|
||||
{
|
||||
if (event_group)
|
||||
if (event_group) {
|
||||
vEventGroupDelete(event_group);
|
||||
}
|
||||
}
|
||||
|
||||
Task::Task(size_t stack_size, size_t priority, void *task_param, TaskFunction_t task_function)
|
||||
:task_handle(nullptr)
|
||||
: 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");
|
||||
@ -87,8 +91,9 @@ Task::Task(size_t stack_size, size_t priority, void *task_param, TaskFunction_t
|
||||
|
||||
Task::~Task()
|
||||
{
|
||||
if (task_handle)
|
||||
if (task_handle) {
|
||||
vTaskDelete(task_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Task::Delete()
|
||||
@ -101,4 +106,9 @@ void Task::Relinquish()
|
||||
vTaskDelay(1);
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
void Task::Delay(uint32_t ms)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(ms));
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
|
@ -46,8 +46,9 @@ void SignalGroup::clear(uint32_t bits)
|
||||
bool SignalGroup::wait(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&]{
|
||||
if ((flags&event_group->flags) == flags) {
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] {
|
||||
if ((flags & event_group->flags) == flags)
|
||||
{
|
||||
event_group->flags &= ~flags;
|
||||
return true;
|
||||
}
|
||||
@ -60,13 +61,13 @@ bool SignalGroup::wait(uint32_t flags, uint32_t time_ms)
|
||||
bool SignalGroup::is_any(uint32_t flags)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return flags&event_group->flags;
|
||||
return flags & event_group->flags;
|
||||
}
|
||||
|
||||
bool SignalGroup::wait_any(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&]{ return flags&event_group->flags; });
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] { return flags & event_group->flags; });
|
||||
}
|
||||
|
||||
SignalGroup::~SignalGroup() = default;
|
||||
@ -88,4 +89,9 @@ void Task::Relinquish()
|
||||
usleep(0);
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
void Task::Delay(uint32_t ms)
|
||||
{
|
||||
usleep(ms*1000);
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
|
@ -14,43 +14,30 @@
|
||||
|
||||
#include <optional>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
#include "esp_log.h"
|
||||
#include "esp_modem_config.h"
|
||||
#include "exception_stub.hpp"
|
||||
#include "uart_resource.hpp" // In case of VFS using UART
|
||||
|
||||
static const char *TAG = "fs_terminal";
|
||||
|
||||
namespace esp_modem {
|
||||
|
||||
class Resource {
|
||||
public:
|
||||
explicit Resource(const esp_modem_dte_config *config, int fd):
|
||||
uart(config->vfs_config.resource == ESP_MODEM_VFS_IS_EXTERN? std::nullopt : std::make_optional<uart_resource>(config, nullptr, fd))
|
||||
{}
|
||||
|
||||
std::optional<uart_resource> uart;
|
||||
};
|
||||
|
||||
struct File {
|
||||
explicit File(const char *name): fd(-1)
|
||||
explicit File(const esp_modem_dte_config *config):
|
||||
fd(config->vfs_config.fd), deleter(config->vfs_config.deleter), resource(config->vfs_config.resource)
|
||||
{}
|
||||
|
||||
~File()
|
||||
{
|
||||
fd = open(name, O_RDWR);
|
||||
throw_if_false(fd >= 0, "Cannot open the fd");
|
||||
|
||||
// Set the FD to non-blocking mode
|
||||
int flags = fcntl(fd, F_GETFL, nullptr) | O_NONBLOCK;
|
||||
fcntl(fd, F_SETFL, flags);
|
||||
}
|
||||
|
||||
~File() {
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
if (deleter) {
|
||||
deleter(fd, resource);
|
||||
}
|
||||
}
|
||||
int fd;
|
||||
void (*deleter)(int fd, struct esp_modem_vfs_resource *res);
|
||||
struct esp_modem_vfs_resource *resource;
|
||||
};
|
||||
|
||||
class FdTerminal : public Terminal {
|
||||
@ -59,11 +46,13 @@ public:
|
||||
|
||||
~FdTerminal() override;
|
||||
|
||||
void start() override {
|
||||
void start() override
|
||||
{
|
||||
signal.set(TASK_START);
|
||||
}
|
||||
|
||||
void stop() override {
|
||||
void stop() override
|
||||
{
|
||||
signal.clear(TASK_START);
|
||||
}
|
||||
|
||||
@ -71,8 +60,9 @@ public:
|
||||
|
||||
int read(uint8_t *data, size_t len) override;
|
||||
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override {
|
||||
on_data = std::move(f);
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override
|
||||
{
|
||||
on_read = std::move(f);
|
||||
signal.set(TASK_PARAMS);
|
||||
}
|
||||
|
||||
@ -85,31 +75,32 @@ private:
|
||||
static const size_t TASK_PARAMS = SignalGroup::bit3;
|
||||
|
||||
File f;
|
||||
Resource resource;
|
||||
SignalGroup signal;
|
||||
Task task_handle;
|
||||
};
|
||||
|
||||
std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config) {
|
||||
std::unique_ptr<Terminal> create_vfs_terminal(const esp_modem_dte_config *config)
|
||||
{
|
||||
TRY_CATCH_RET_NULL(
|
||||
auto term = std::make_unique<FdTerminal>(config);
|
||||
term->start();
|
||||
return term;
|
||||
auto term = std::make_unique<FdTerminal>(config);
|
||||
term->start();
|
||||
return term;
|
||||
)
|
||||
}
|
||||
|
||||
FdTerminal::FdTerminal(const esp_modem_dte_config *config) :
|
||||
f(config->vfs_config.dev_name), resource(config, f.fd), signal(),
|
||||
task_handle(config->task_stack_size, config->task_priority, this, [](void* p){
|
||||
auto t = static_cast<FdTerminal *>(p);
|
||||
t->task();
|
||||
Task::Delete();
|
||||
})
|
||||
{}
|
||||
f(config), signal(),
|
||||
task_handle(config->task_stack_size, config->task_priority, this, [](void *p)
|
||||
{
|
||||
auto t = static_cast<FdTerminal *>(p);
|
||||
t->task();
|
||||
Task::Delete();
|
||||
})
|
||||
{}
|
||||
|
||||
void FdTerminal::task()
|
||||
{
|
||||
std::function<bool(uint8_t *data, size_t len)> on_data_priv = nullptr;
|
||||
std::function<bool(uint8_t *data, size_t len)> on_read_priv = nullptr;
|
||||
signal.set(TASK_INIT);
|
||||
signal.wait_any(TASK_START | TASK_STOP, portMAX_DELAY);
|
||||
if (signal.is_any(TASK_STOP)) {
|
||||
@ -120,15 +111,15 @@ void FdTerminal::task()
|
||||
int s;
|
||||
fd_set rfds;
|
||||
struct timeval tv = {
|
||||
.tv_sec = 1,
|
||||
.tv_usec = 0,
|
||||
.tv_sec = 1,
|
||||
.tv_usec = 0,
|
||||
};
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(f.fd, &rfds);
|
||||
|
||||
s = select(f.fd + 1, &rfds, nullptr, nullptr, &tv);
|
||||
if (signal.is_any(TASK_PARAMS)) {
|
||||
on_data_priv = on_data;
|
||||
on_read_priv = on_read;
|
||||
signal.clear(TASK_PARAMS);
|
||||
}
|
||||
|
||||
@ -138,9 +129,9 @@ void FdTerminal::task()
|
||||
// ESP_LOGV(TAG, "Select exited with timeout");
|
||||
} else {
|
||||
if (FD_ISSET(f.fd, &rfds)) {
|
||||
if (on_data_priv) {
|
||||
if (on_data_priv(nullptr, 0)) {
|
||||
on_data_priv = nullptr;
|
||||
if (on_read_priv) {
|
||||
if (on_read_priv(nullptr, 0)) {
|
||||
on_read_priv = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,51 +25,51 @@ uart_resource::~uart_resource()
|
||||
}
|
||||
}
|
||||
|
||||
uart_resource::uart_resource(const esp_modem_dte_config *config, struct QueueDefinition** event_queue, int fd)
|
||||
:port(-1)
|
||||
uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHandle_t *event_queue, int fd)
|
||||
: port(-1)
|
||||
{
|
||||
esp_err_t res;
|
||||
|
||||
/* Config UART */
|
||||
uart_config_t uart_config = {};
|
||||
uart_config.baud_rate = config->uart_config.baud_rate;
|
||||
uart_config.data_bits = config->uart_config.data_bits;
|
||||
uart_config.parity = config->uart_config.parity;
|
||||
uart_config.stop_bits = config->uart_config.stop_bits;
|
||||
uart_config.flow_ctrl = (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS
|
||||
: UART_HW_FLOWCTRL_DISABLE;
|
||||
uart_config.baud_rate = config->baud_rate;
|
||||
uart_config.data_bits = config->data_bits;
|
||||
uart_config.parity = config->parity;
|
||||
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;
|
||||
|
||||
throw_if_esp_fail(uart_param_config(config->uart_config.port_num, &uart_config), "config uart parameter failed");
|
||||
throw_if_esp_fail(uart_param_config(config->port_num, &uart_config), "config uart parameter failed");
|
||||
|
||||
if (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
res = uart_set_pin(config->uart_config.port_num, config->uart_config.tx_io_num, config->uart_config.rx_io_num,
|
||||
config->uart_config.rts_io_num, config->uart_config.cts_io_num);
|
||||
if (config->flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
res = uart_set_pin(config->port_num, config->tx_io_num, config->rx_io_num,
|
||||
config->rts_io_num, config->cts_io_num);
|
||||
} else {
|
||||
res = uart_set_pin(config->uart_config.port_num, config->uart_config.tx_io_num, config->uart_config.rx_io_num,
|
||||
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");
|
||||
/* Set flow control threshold */
|
||||
if (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
res = uart_set_hw_flow_ctrl(config->uart_config.port_num, UART_HW_FLOWCTRL_CTS_RTS, UART_FIFO_LEN - 8);
|
||||
} else if (config->uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_SW) {
|
||||
res = uart_set_sw_flow_ctrl(config->uart_config.port_num, true, 8, UART_FIFO_LEN - 8);
|
||||
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");
|
||||
|
||||
/* Install UART driver and get event queue used inside driver */
|
||||
res = uart_driver_install(config->uart_config.port_num,
|
||||
config->uart_config.rx_buffer_size, config->uart_config.tx_buffer_size,
|
||||
config->uart_config.event_queue_size, config->uart_config.event_queue_size ? event_queue : nullptr,
|
||||
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->uart_config.port_num, 1), "set rx timeout failed");
|
||||
throw_if_esp_fail(uart_set_rx_timeout(config->port_num, 1), "set rx timeout failed");
|
||||
|
||||
throw_if_esp_fail(uart_set_rx_full_threshold(config->uart_config.port_num, 64), "config rx full threshold failed");
|
||||
throw_if_esp_fail(uart_set_rx_full_threshold(config->port_num, 64), "config rx full threshold failed");
|
||||
|
||||
/* mark UART as initialized */
|
||||
port = config->uart_config.port_num;
|
||||
port = config->port_num;
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/uart.h"
|
||||
#include "uart_compat.h"
|
||||
#include "esp_modem_config.h"
|
||||
#include "exception_stub.hpp"
|
||||
#include "cxx_include/esp_modem_dte.hpp"
|
||||
@ -29,13 +30,17 @@ namespace esp_modem {
|
||||
|
||||
struct uart_task {
|
||||
explicit uart_task(size_t stack_size, size_t priority, void *task_param, TaskFunction_t task_function) :
|
||||
task_handle(nullptr) {
|
||||
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");
|
||||
}
|
||||
|
||||
~uart_task() {
|
||||
if (task_handle) vTaskDelete(task_handle);
|
||||
~uart_task()
|
||||
{
|
||||
if (task_handle) {
|
||||
vTaskDelete(task_handle);
|
||||
}
|
||||
}
|
||||
|
||||
TaskHandle_t task_handle; /*!< UART event task handle */
|
||||
@ -46,16 +51,18 @@ struct uart_task {
|
||||
class UartTerminal : public Terminal {
|
||||
public:
|
||||
explicit UartTerminal(const esp_modem_dte_config *config) :
|
||||
event_queue(), uart(config, &event_queue, -1), signal(),
|
||||
task_handle(config->task_stack_size, config->task_priority, this, s_task) {}
|
||||
event_queue(), uart(&config->uart_config, &event_queue, -1), signal(),
|
||||
task_handle(config->task_stack_size, config->task_priority, this, s_task) {}
|
||||
|
||||
~UartTerminal() override = default;
|
||||
|
||||
void start() override {
|
||||
void start() override
|
||||
{
|
||||
signal.set(TASK_START);
|
||||
}
|
||||
|
||||
void stop() override {
|
||||
void stop() override
|
||||
{
|
||||
signal.set(TASK_STOP);
|
||||
}
|
||||
|
||||
@ -63,24 +70,28 @@ public:
|
||||
|
||||
int read(uint8_t *data, size_t len) override;
|
||||
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override {
|
||||
on_data = std::move(f);
|
||||
void set_read_cb(std::function<bool(uint8_t *data, size_t len)> f) override
|
||||
{
|
||||
on_read = std::move(f);
|
||||
signal.set(TASK_PARAMS);
|
||||
}
|
||||
|
||||
private:
|
||||
static void s_task(void *task_param) {
|
||||
static void s_task(void *task_param)
|
||||
{
|
||||
auto t = static_cast<UartTerminal *>(task_param);
|
||||
t->task();
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
void task();
|
||||
bool get_event(uart_event_t &event, uint32_t time_ms) {
|
||||
bool get_event(uart_event_t &event, uint32_t time_ms)
|
||||
{
|
||||
return xQueueReceive(event_queue, &event, pdMS_TO_TICKS(time_ms));
|
||||
}
|
||||
|
||||
void reset_events() {
|
||||
void reset_events()
|
||||
{
|
||||
uart_flush_input(uart.port);
|
||||
xQueueReset(event_queue);
|
||||
}
|
||||
@ -96,16 +107,18 @@ private:
|
||||
uart_task task_handle;
|
||||
};
|
||||
|
||||
std::unique_ptr<Terminal> create_uart_terminal(const esp_modem_dte_config *config) {
|
||||
std::unique_ptr<Terminal> create_uart_terminal(const esp_modem_dte_config *config)
|
||||
{
|
||||
TRY_CATCH_RET_NULL(
|
||||
auto term = std::make_unique<UartTerminal>(config);
|
||||
term->start();
|
||||
return term;
|
||||
auto term = std::make_unique<UartTerminal>(config);
|
||||
term->start();
|
||||
return term;
|
||||
)
|
||||
}
|
||||
|
||||
void UartTerminal::task() {
|
||||
std::function<bool(uint8_t *data, size_t len)> on_data_priv = nullptr;
|
||||
void UartTerminal::task()
|
||||
{
|
||||
std::function<bool(uint8_t *data, size_t len)> on_read_priv = nullptr;
|
||||
uart_event_t event;
|
||||
size_t len;
|
||||
signal.set(TASK_INIT);
|
||||
@ -116,54 +129,60 @@ void UartTerminal::task() {
|
||||
while (signal.is_any(TASK_START)) {
|
||||
if (get_event(event, 100)) {
|
||||
if (signal.is_any(TASK_PARAMS)) {
|
||||
on_data_priv = on_data;
|
||||
on_read_priv = on_read;
|
||||
signal.clear(TASK_PARAMS);
|
||||
}
|
||||
switch (event.type) {
|
||||
case UART_DATA:
|
||||
uart_get_buffered_data_len(uart.port, &len);
|
||||
if (len && on_data_priv) {
|
||||
if (on_data_priv(nullptr, len)) {
|
||||
on_data_priv = nullptr;
|
||||
}
|
||||
case UART_DATA:
|
||||
uart_get_buffered_data_len(uart.port, &len);
|
||||
if (len && on_read_priv) {
|
||||
if (on_read_priv(nullptr, len)) {
|
||||
on_read_priv = nullptr;
|
||||
}
|
||||
break;
|
||||
case UART_FIFO_OVF:
|
||||
ESP_LOGW(TAG, "HW FIFO Overflow");
|
||||
if (on_error)
|
||||
on_error(terminal_error::BUFFER_OVERFLOW);
|
||||
reset_events();
|
||||
break;
|
||||
case UART_BUFFER_FULL:
|
||||
ESP_LOGW(TAG, "Ring Buffer Full");
|
||||
if (on_error)
|
||||
on_error(terminal_error::BUFFER_OVERFLOW);
|
||||
reset_events();
|
||||
break;
|
||||
case UART_BREAK:
|
||||
ESP_LOGW(TAG, "Rx Break");
|
||||
if (on_error)
|
||||
on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
|
||||
break;
|
||||
case UART_PARITY_ERR:
|
||||
ESP_LOGE(TAG, "Parity Error");
|
||||
if (on_error)
|
||||
on_error(terminal_error::CHECKSUM_ERROR);
|
||||
break;
|
||||
case UART_FRAME_ERR:
|
||||
ESP_LOGE(TAG, "Frame Error");
|
||||
if (on_error)
|
||||
on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "unknown uart event type: %d", event.type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case UART_FIFO_OVF:
|
||||
ESP_LOGW(TAG, "HW FIFO Overflow");
|
||||
if (on_error) {
|
||||
on_error(terminal_error::BUFFER_OVERFLOW);
|
||||
}
|
||||
reset_events();
|
||||
break;
|
||||
case UART_BUFFER_FULL:
|
||||
ESP_LOGW(TAG, "Ring Buffer Full");
|
||||
if (on_error) {
|
||||
on_error(terminal_error::BUFFER_OVERFLOW);
|
||||
}
|
||||
reset_events();
|
||||
break;
|
||||
case UART_BREAK:
|
||||
ESP_LOGW(TAG, "Rx Break");
|
||||
if (on_error) {
|
||||
on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
|
||||
}
|
||||
break;
|
||||
case UART_PARITY_ERR:
|
||||
ESP_LOGE(TAG, "Parity Error");
|
||||
if (on_error) {
|
||||
on_error(terminal_error::CHECKSUM_ERROR);
|
||||
}
|
||||
break;
|
||||
case UART_FRAME_ERR:
|
||||
ESP_LOGE(TAG, "Frame Error");
|
||||
if (on_error) {
|
||||
on_error(terminal_error::UNEXPECTED_CONTROL_FLOW);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "unknown uart event type: %d", event.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int UartTerminal::read(uint8_t *data, size_t len) {
|
||||
int UartTerminal::read(uint8_t *data, size_t len)
|
||||
{
|
||||
size_t length = 0;
|
||||
uart_get_buffered_data_len(uart.port, &length);
|
||||
length = std::min(len, length);
|
||||
@ -173,8 +192,9 @@ int UartTerminal::read(uint8_t *data, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UartTerminal::write(uint8_t *data, size_t len) {
|
||||
return uart_write_bytes(uart.port, data, len);
|
||||
int UartTerminal::write(uint8_t *data, size_t len)
|
||||
{
|
||||
return uart_write_bytes_compat(uart.port, data, len);
|
||||
}
|
||||
|
||||
} // namespace esp_modem
|
||||
|
@ -23,7 +23,7 @@ namespace esp_modem {
|
||||
|
||||
constexpr const char *TAG = "uart_resource";
|
||||
|
||||
uart_resource::uart_resource(const esp_modem_dte_config *config, struct QueueDefinition** event_queue, int fd): port(-1)
|
||||
uart_resource::uart_resource(const esp_modem_uart_term_config *config, QueueHandle_t *event_queue, int fd): port(-1)
|
||||
{
|
||||
ESP_LOGD(TAG, "Creating uart resource" );
|
||||
struct termios tty = {};
|
||||
@ -39,7 +39,7 @@ uart_resource::uart_resource(const esp_modem_dte_config *config, struct QueueDef
|
||||
tty.c_lflag &= ~ECHO; // Disable echo
|
||||
tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
|
||||
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
|
||||
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes
|
||||
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes
|
||||
tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
|
||||
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
|
||||
tty.c_cc[VTIME] = 0;
|
||||
|
104
components/esp_modem/src/esp_modem_vfs_socket_creator.cpp
Normal file
104
components/esp_modem/src/esp_modem_vfs_socket_creator.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_modem_config.h"
|
||||
#include "cxx_include/esp_modem_exception.hpp"
|
||||
#include "exception_stub.hpp"
|
||||
#include "uart_resource.hpp"
|
||||
#include "vfs_resource/vfs_create.hpp"
|
||||
|
||||
|
||||
constexpr const char *TAG = "vfs_socket_creator";
|
||||
|
||||
/**
|
||||
* @brief socket VFS
|
||||
* @note: Remote command:
|
||||
* socat TCP-L:2222 GOPEN:/dev/ttyS0,ispeed=115200,ospeed=1152000,b115200,raw,echo=0
|
||||
*/
|
||||
static esp_err_t hostname_to_fd(const char *host, int port, int *fd)
|
||||
{
|
||||
struct sockaddr_storage address = {};
|
||||
struct addrinfo *address_info;
|
||||
struct addrinfo hints = {};
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
int res = getaddrinfo(host, nullptr, &hints, &address_info);
|
||||
if (res != 0 || address_info == nullptr) {
|
||||
ESP_LOGE(TAG, "couldn't get hostname for :%s: "
|
||||
"getaddrinfo() returns %d, addrinfo=%p", host, res, address_info);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
*fd = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
|
||||
if (*fd < 0) {
|
||||
ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
|
||||
freeaddrinfo(address_info);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (address_info->ai_family == AF_INET) {
|
||||
auto *p = reinterpret_cast<struct sockaddr_in *>(address_info->ai_addr);
|
||||
p->sin_port = htons(port);
|
||||
ESP_LOGI(TAG, "[sock=%d] Resolved IPv4 address: %s", *fd, inet_ntoa(p->sin_addr));
|
||||
memcpy(&address, p, sizeof(struct sockaddr ));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Unsupported protocol family %d", address_info->ai_family);
|
||||
close(*fd);
|
||||
freeaddrinfo(address_info);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
freeaddrinfo(address_info);
|
||||
if (connect(*fd, (struct sockaddr *)&address, sizeof(struct sockaddr)) < 0) {
|
||||
ESP_LOGE(TAG, "[sock=%d] Failed to connect", *fd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static void vfs_destroy_socket(int fd, struct esp_modem_vfs_resource *resource)
|
||||
{
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
bool vfs_create_socket(struct esp_modem_vfs_socket_creator *config, struct esp_modem_vfs_term_config *created_config)
|
||||
{
|
||||
if (config == nullptr || created_config == nullptr) {
|
||||
return false;
|
||||
}
|
||||
TRY_CATCH_OR_DO(
|
||||
int fd = -1;
|
||||
esp_modem::throw_if_esp_fail(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;
|
||||
fcntl(fd, F_SETFL, flags);
|
||||
|
||||
created_config->fd = fd;
|
||||
created_config->deleter = vfs_destroy_socket;
|
||||
, return false)
|
||||
return true;
|
||||
}
|
64
components/esp_modem/src/esp_modem_vfs_uart_creator.cpp
Normal file
64
components/esp_modem/src/esp_modem_vfs_uart_creator.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <optional>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_modem_config.h"
|
||||
#include "cxx_include/esp_modem_exception.hpp"
|
||||
#include "exception_stub.hpp"
|
||||
#include "uart_resource.hpp"
|
||||
#include "vfs_resource/vfs_create.hpp"
|
||||
|
||||
constexpr const char *TAG = "vfs_uart_creator";
|
||||
|
||||
|
||||
struct esp_modem_vfs_resource {
|
||||
explicit esp_modem_vfs_resource(const esp_modem_uart_term_config *config, int fd)
|
||||
: internal(config, nullptr, fd) {}
|
||||
|
||||
esp_modem::uart_resource internal;
|
||||
};
|
||||
|
||||
|
||||
static void vfs_destroy_uart(int fd, struct esp_modem_vfs_resource *resource)
|
||||
{
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
delete resource;
|
||||
}
|
||||
|
||||
bool vfs_create_uart(struct esp_modem_vfs_uart_creator *config, struct esp_modem_vfs_term_config *created_config)
|
||||
{
|
||||
if (!config->dev_name || created_config == nullptr) {
|
||||
return false;
|
||||
}
|
||||
TRY_CATCH_OR_DO(
|
||||
int fd = open(config->dev_name, O_RDWR);
|
||||
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;
|
||||
created_config->deleter = vfs_destroy_uart;
|
||||
|
||||
// Set the FD to non-blocking mode
|
||||
int flags = fcntl(fd, F_GETFL, nullptr) | O_NONBLOCK;
|
||||
fcntl(fd, F_SETFL, flags);
|
||||
|
||||
, return false)
|
||||
|
||||
return true;
|
||||
}
|
@ -15,8 +15,8 @@ void LoopbackTerm::stop()
|
||||
|
||||
int LoopbackTerm::write(uint8_t *data, size_t len)
|
||||
{
|
||||
if (len > 2 && (data[len-1] == '\r' || data[len-1] == '+') ) { // Simple AT responder
|
||||
std::string command((char*)data, len);
|
||||
if (len > 2 && (data[len - 1] == '\r' || data[len - 1] == '+') ) { // Simple AT responder
|
||||
std::string command((char *)data, len);
|
||||
std::string response;
|
||||
if (command == "+++") {
|
||||
response = "NO CARRIER\r\n";
|
||||
@ -28,14 +28,16 @@ int LoopbackTerm::write(uint8_t *data, size_t len)
|
||||
response = "CONNECT\r\n";
|
||||
} else if (command.find("AT+CSQ\r") != std::string::npos) {
|
||||
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+CBC\r") != std::string::npos) {
|
||||
response = is_bg96 ? "+CBC: 1,2,123456V\r\r\n\r\nOK\r\n\n\r\n":
|
||||
"+CBC: 123.456V\r\r\n\r\nOK\r\n\n\r\n";
|
||||
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";
|
||||
} else if (command.find("AT+CPIN=1234\r") != std::string::npos) {
|
||||
response = "OK\r\n";
|
||||
pin_ok = true;
|
||||
} else if (command.find("AT+CPIN?\r") != std::string::npos) {
|
||||
response = pin_ok?"+CPIN: READY\r\nOK\r\n":"+CPIN: SIM PIN\r\nOK\r\n";
|
||||
response = pin_ok ? "+CPIN: READY\r\nOK\r\n" : "+CPIN: SIM PIN\r\nOK\r\n";
|
||||
} else if (command.find("AT") != std::string::npos) {
|
||||
response = "OK\r\n";
|
||||
}
|
||||
@ -43,22 +45,22 @@ int LoopbackTerm::write(uint8_t *data, size_t len)
|
||||
data_len = response.length();
|
||||
loopback_data.resize(data_len);
|
||||
memcpy(&loopback_data[0], &response[0], data_len);
|
||||
auto ret = std::async(on_data, nullptr, data_len);
|
||||
auto ret = std::async(on_read, nullptr, data_len);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
if (len > 2 && data[0] == 0xf9) { // Simple CMUX responder
|
||||
// turn the request into a reply -> implements CMUX loopback
|
||||
if (data[2] == 0x3f) // SABM command
|
||||
if (data[2] == 0x3f) { // SABM command
|
||||
data[2] = 0x73;
|
||||
else if (data[2] == 0xef) { // Generic request
|
||||
} else if (data[2] == 0xef) { // Generic request
|
||||
data[2] = 0xff; // generic reply
|
||||
}
|
||||
}
|
||||
loopback_data.resize(data_len + len);
|
||||
memcpy(&loopback_data[data_len], data, len);
|
||||
data_len += len;
|
||||
auto ret = std::async(on_data, nullptr, data_len);
|
||||
auto ret = std::async(on_read, nullptr, data_len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -66,8 +68,9 @@ int LoopbackTerm::read(uint8_t *data, size_t len)
|
||||
{
|
||||
size_t read_len = std::min(data_len, len);
|
||||
if (read_len) {
|
||||
if (loopback_data.capacity() < len)
|
||||
if (loopback_data.capacity() < len) {
|
||||
loopback_data.reserve(len);
|
||||
}
|
||||
memcpy(data, &loopback_data[0], read_len);
|
||||
loopback_data.erase(loopback_data.begin(), loopback_data.begin() + read_len);
|
||||
data_len -= read_len;
|
||||
|
@ -1,5 +1,4 @@
|
||||
#ifndef _LOOPBACKTERM_H_
|
||||
#define _LOOPBACKTERM_H_
|
||||
#pragma once
|
||||
|
||||
#include "cxx_include/esp_modem_api.hpp"
|
||||
#include "cxx_include/esp_modem_terminal.hpp"
|
||||
@ -32,5 +31,3 @@ private:
|
||||
bool pin_ok;
|
||||
bool is_bg96;
|
||||
};
|
||||
|
||||
#endif //_LOOPBACKTERM_H_
|
||||
|
@ -24,7 +24,7 @@ TEST_CASE("DCE AT parser", "[esp_modem]")
|
||||
CHECK(dce->get_battery_status(milli_volt, bcl, bcs) == command_result::OK);
|
||||
CHECK(milli_volt == 123456);
|
||||
CHECK(bcl == 1);
|
||||
CHECK(bcs == 2);
|
||||
CHECK(bcs == 20);
|
||||
|
||||
int rssi, ber;
|
||||
CHECK(dce->get_signal_quality(rssi, ber) == command_result::OK);
|
||||
@ -37,6 +37,10 @@ TEST_CASE("DCE AT parser", "[esp_modem]")
|
||||
CHECK(dce->set_pin("1234") == command_result::OK);
|
||||
CHECK(dce->read_pin(pin_ok) == command_result::OK);
|
||||
CHECK(pin_ok == true);
|
||||
|
||||
std::string model;
|
||||
CHECK(dce->get_module_name(model) == command_result::OK);
|
||||
CHECK(model == "0G Dummy Model");
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +55,7 @@ TEST_CASE("DTE send/receive command", "[esp_modem]")
|
||||
CHECK(dte->set_mode(esp_modem::modem_mode::COMMAND_MODE) == true);
|
||||
|
||||
auto ret = dte->command(test_command, [&](uint8_t *data, size_t len) {
|
||||
std::string response((char*)data, len);
|
||||
std::string response((char *)data, len);
|
||||
CHECK(response == test_command);
|
||||
return command_result::OK;
|
||||
}, 1000);
|
||||
@ -71,7 +75,7 @@ TEST_CASE("DCE commands", "[esp_modem]")
|
||||
|
||||
const auto test_command = "Test\n";
|
||||
auto ret = dce->command(test_command, [&](uint8_t *data, size_t len) {
|
||||
std::string response((char*)data, len);
|
||||
std::string response((char *)data, len);
|
||||
CHECK(response == test_command);
|
||||
return command_result::OK;
|
||||
}, 1000);
|
||||
@ -114,7 +118,8 @@ TEST_CASE("DCE modes", "[esp_modem]")
|
||||
CHECK(dce->set_mode(esp_modem::modem_mode::COMMAND_MODE) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("DCE CMUX test", "[esp_modem]") {
|
||||
TEST_CASE("DCE CMUX test", "[esp_modem]")
|
||||
{
|
||||
auto term = std::make_unique<LoopbackTerm>();
|
||||
auto dte = std::make_shared<DTE>(std::move(term));
|
||||
CHECK(term == nullptr);
|
||||
|
@ -1,74 +0,0 @@
|
||||
#
|
||||
# Automatically generated file. DO NOT EDIT.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Configuration
|
||||
#
|
||||
CONFIG_IDF_CMAKE=y
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_IDF_FIRMWARE_CHIP_ID=0xFFFF
|
||||
|
||||
#
|
||||
# SDK tool configuration
|
||||
#
|
||||
CONFIG_SDK_TOOLPREFIX=""
|
||||
# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
|
||||
# end of SDK tool configuration
|
||||
|
||||
#
|
||||
# Build type
|
||||
#
|
||||
CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
|
||||
# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
|
||||
CONFIG_APP_BUILD_GENERATE_BINARIES=y
|
||||
CONFIG_APP_BUILD_BOOTLOADER=y
|
||||
CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
|
||||
# end of Build type
|
||||
|
||||
#
|
||||
# Compiler options
|
||||
#
|
||||
CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
|
||||
CONFIG_COMPILER_HIDE_PATHS_MACROS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
||||
CONFIG_COMPILER_CXX_RTTI=y
|
||||
CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
|
||||
# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
|
||||
# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
|
||||
# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
|
||||
# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
|
||||
# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
|
||||
# CONFIG_COMPILER_DUMP_RTL_FILES is not set
|
||||
# end of Compiler options
|
||||
|
||||
#
|
||||
# Component config
|
||||
#
|
||||
|
||||
#
|
||||
# Compatibility options
|
||||
#
|
||||
# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
|
||||
# end of Compatibility options
|
||||
|
||||
# Deprecated options for backward compatibility
|
||||
CONFIG_TOOLPREFIX=""
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
|
||||
CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
|
||||
# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||
# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
|
||||
CONFIG_CXX_EXCEPTIONS=y
|
||||
CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
||||
CONFIG_STACK_CHECK_NONE=y
|
||||
# CONFIG_STACK_CHECK_NORM is not set
|
||||
# CONFIG_STACK_CHECK_STRONG is not set
|
||||
# CONFIG_STACK_CHECK_ALL is not set
|
||||
# CONFIG_WARN_WRITE_STRINGS is not set
|
||||
# CONFIG_DISABLE_GCC8_WARNINGS is not set
|
||||
# End of deprecated options
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user