Documentaton generation completed

This commit is contained in:
David Cermak
2021-04-14 17:57:42 +02:00
parent d384cde725
commit 4bf8ab07ca
27 changed files with 509 additions and 88 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 139 KiB

View File

@ -829,10 +829,23 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = c_api.h cpp_api.h ../include/esp_modem_api.h \ INPUT = ../include/esp_modem_api.h \
../include/esp_modem_c_api_types.h \ ../include/esp_modem_c_api_types.h \
../include/cxx_include/esp_modem_api.hpp \ ../include/cxx_include/esp_modem_api.hpp \
../include/cxx_include/esp_modem_dce.hpp ../include/cxx_include/esp_modem_dce.hpp \
../include/esp_modem_config.h \
../include/esp_modem_dce_config.h \
../include/cxx_include/esp_modem_dce_factory.hpp \
../include/cxx_include/esp_modem_command_library.hpp \
../include/cxx_include/esp_modem_dce_module.hpp \
../include/cxx_include/esp_modem_dte.hpp \
../include/cxx_include/esp_modem_netif.hpp \
../include/cxx_include/esp_modem_types.hpp \
../include/cxx_include/esp_modem_terminal.hpp \
../include/cxx_include/esp_modem_cmux.hpp \
esp_modem_api_commands.h \
esp_modem_dce.hpp
# The last two are generated
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -947,7 +960,7 @@ IMAGE_PATH =
# need to set EXTENSION_MAPPING for the extension otherwise the files are not # need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen. # properly processed by doxygen.
INPUT_FILTER = "sed 's/std::unique_ptr<\(.*\)>/\1*/;s/std::shared_ptr<\(.*\)>/\1*/'" #INPUT_FILTER = "sed 's/std::unique_ptr<\(.*\)>/\1*/;s/std::shared_ptr<\(.*\)>/\1*/'"
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the # basis. Doxygen will compare the file name with each pattern and apply the
@ -1103,7 +1116,7 @@ IGNORE_PREFIX =
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES. # The default value is: YES.
GENERATE_HTML = YES GENERATE_HTML = NO
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@ -1658,7 +1671,7 @@ EXTRA_SEARCH_MAPPINGS =
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES. # The default value is: YES.
GENERATE_LATEX = YES GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@ -2459,7 +2472,7 @@ DOT_GRAPH_MAX_NODES = 250
# Minimum value: 0, maximum value: 1000, default value: 0. # Minimum value: 0, maximum value: 1000, default value: 0.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
MAX_DOT_GRAPH_DEPTH = 10 MAX_DOT_GRAPH_DEPTH = 3
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem # background. This is disabled by default, because dot on Windows does not seem
@ -2508,4 +2521,5 @@ DOT_CLEANUP = YES
#TEMPLATE_RELATIONS = YES #TEMPLATE_RELATIONS = YES
#DOT_GRAPH_MAX_NODES = 100 #DOT_GRAPH_MAX_NODES = 100
#MAX_DOT_GRAPH_DEPTH = 0 #MAX_DOT_GRAPH_DEPTH = 0
#DOT_TRANSPARENT = YES #DOT_TRANSPARENT = YES

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

View File

@ -1,15 +1,45 @@
Advanced esp-modem use cases Advanced esp-modem use cases
============================ ============================
Create custom modem instance with DCE factory This chapter outlines basic extensibility of the esp-modem component.
---------------------------------------------
.. _dce_factory:
Custom instantiation with DCE factory
--------------------------------------
It is possible to create a modem handle in many different ways:
- Build a DCE on top a generic module, user defined module or build the module only (in case the application will only use AT command interface)
- Create the DCE as a shared, unique or a vanilla pointer
- Create a generic DCE or a templated DCE_T of a specific module (this could be one of the supported modules or a user defined module)
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
the specific module, using :cpp:func:`esp_modem::dce_factory::Factory::build`.
Please refer to the implementation of the existing modules.
Create new communication interface Create new communication interface
---------------------------------- ----------------------------------
In order to connect to a device using an unsuppoeted 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.
- Create the DTE which uses the custom Terminal
Please refer to the implementation of the existing UART DTE.

View File

@ -18,6 +18,7 @@ Typical application workflow is to:
- Optionally switch back to command mode (again :cpp:func:`esp_modem_set_mode`) - Optionally switch back to command mode (again :cpp:func:`esp_modem_set_mode`)
- Destroy the DCE handle (sing :cpp:func:`esp_modem_destroy`) - Destroy the DCE handle (sing :cpp:func:`esp_modem_destroy`)
Note the configuration structures for DTE and DCE, needed for creating the DCE instance, is documented in :ref:`api_config`
.. _lifecycle_api: .. _lifecycle_api:
@ -26,6 +27,10 @@ Lifecycle API
These functions are used to create, destroy and set modem working mode. These functions are used to create, destroy and set modem working mode.
- :cpp:func:`esp_modem_new`
- :cpp:func:`esp_modem_destroy`
- :cpp:func:`esp_modem_set_mode`
.. doxygengroup:: ESP_MODEM_C_API .. doxygengroup:: ESP_MODEM_C_API
@ -37,4 +42,13 @@ Modem commands
These functions are the actual commands to communicate with the modem using AT command interface. These functions are the actual commands to communicate with the modem using AT command interface.
.. doxygenfile:: c_api.h .. doxygenfile:: esp_modem_api_commands.h
.. _api_config:
Configuration structures
------------------------
.. doxygengroup:: ESP_MODEM_CONFIG
:members:

View File

@ -9,14 +9,14 @@ import subprocess
import sys import sys
# General information about the project. # General information about the project.
project = u'ESP-MODEM Documentation' project = u'esp-modem'
copyright = u'2016 - 2021, Espressif Systems (Shanghai) Co., Ltd' copyright = u'2016 - 2021, Espressif Systems (Shanghai) Co., Ltd'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
language = 'en' language = 'en'
extensions = ['breathe' ] extensions = ['breathe']
breathe_projects = {'esp_modem': 'xml'} breathe_projects = {'esp_modem': 'xml'}

View File

@ -3,10 +3,14 @@ C++ API Documentation
Similar to the :ref:`c_api`, the basic application workflow consist of Similar to the :ref:`c_api`, the basic application workflow consist of
- Construction of the DCE .. toctree::
- Sending (AT) commands
- Switching modes - :ref:`Construction of the DCE<cpp_init>`
- Destroying the DCE - :ref:`Switching modes<cpp_mode_switch>`
- :ref:`Sending (AT) commands<cpp_modem_commands>`
- :ref:`Destroying the DCE<cpp_destroy>`
.. _cpp_init:
Create DTE and DCE Create DTE and DCE
------------------ ------------------
@ -16,21 +20,22 @@ Create DTE and DCE
.. doxygengroup:: ESP_MODEM_INIT_DCE .. doxygengroup:: ESP_MODEM_INIT_DCE
.. _cpp_mode_switch:
Mode switching commands Mode switching commands
----------------------- -----------------------
.. doxygenclass:: esp_modem::DCE_T .. doxygenclass:: esp_modem::DCE_T
:members: :members:
.. _cpp_modem_commands:
Modem commands Modem commands
-------------- --------------
Create the DCE object with DCE factory :cpp:func:`esp_modem_new` .. include:: cxx_api_links.rst
.. doxygenclass:: DCE
:members:
.. _cpp_destroy:
Destroy the DCE Destroy the DCE
--------------- ---------------

View File

@ -0,0 +1,13 @@
- :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::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`

View File

@ -1,4 +1,5 @@
// 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 -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
// --- DCE command documentation starts here --- // --- DCE command documentation starts here ---
/** /**
* @brief Sends the supplied PIN code * @brief Sends the supplied PIN code

View File

@ -1,6 +1,8 @@
// 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
// --- DCE command documentation starts here --- // --- DCE command documentation starts here ---
class DCE: public DCE_T<GenericModule> { class esp_modem::DCE: public DCE_T<GenericModule> {
public: public:
using DCE_T<GenericModule>::DCE_T; using DCE_T<GenericModule>::DCE_T;
@ -9,6 +11,7 @@ public:
/** /**
* @brief Sends the supplied PIN code * @brief Sends the supplied PIN code
* *

View File

@ -1,2 +1,20 @@
# Cleanup the generated html
rm -rf html
# Generate C++ API header of the DCE
cat ../include/generate/esp_modem_command_declare.inc | clang++ -E -P -CC -xc++ -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > esp_modem_dce.hpp
# Generate C API header of the modem_api.h
cat ../include/generate/esp_modem_command_declare.inc | clang -E -P -CC -xc -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' > esp_modem_api_commands.h
# RST with links to C++ API
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
# Run doxygen
doxygen
# Generate the docs
python -u -m sphinx.cmd.build -b html . html python -u -m sphinx.cmd.build -b html . html
# Cleanup the doxygen xml's
rm -rf xml

View File

@ -1,5 +1,5 @@
ESP-MODEM Documentation ESP-MODEM Programmers manual
======================= ============================
.. toctree:: .. toctree::
@ -8,4 +8,4 @@ ESP-MODEM Documentation
C++ interface <cxx_api_docs> C++ interface <cxx_api_docs>
Advanced use cases <advanced_api> Advanced use cases <advanced_api>
Internal design <internal_design> Internal design <internal_design>
Internal implementation <internal_docs>

View File

@ -3,45 +3,14 @@
## Design decisions ## Design decisions
* Use C++ with additional C API * Use C++ with additional C API
| esp-modem in C | esp-modem in C++ |
|----------------|---------------|
```
+2282
-3908
```
* Use exceptions * Use exceptions
- Use macro wrapper over `try-catch` blocks when exceptions off (use `abort()` if `THROW()`) - Use macro wrapper over `try-catch` blocks when exceptions off (use `abort()` if `THROW()`)
| exceptions off | exceptions on |
|----------------|---------------|
```
Difference is counted as <CURRENT> - <REFERENCE>, i.e. a positive number means that <CURRENT> is larger.
Total sizes of <CURRENT>: <REFERENCE> Difference
DRAM .data size: 10996 bytes 10996
DRAM .bss size: 12552 bytes 12488 +64
Used static DRAM: 23548 bytes ( 157188 available, 13.0% used) 23484 +64 ( -64 available, +0 total)
Used static IRAM: 54145 bytes ( 76927 available, 41.3% used) 54093 +52 ( -52 available, +0 total)
Flash code: 603979 bytes 595551 +8428
Flash rodata: 187772 bytes 177852 +9920
Total image size:~ 869444 bytes (.bin may be padded larger) 850980 +18464
```
| exceptions on | RTTI on |
|----------------|---------------|
```
Total sizes of <CURRENT>: <REFERENCE> Difference
DRAM .data size: 10996 bytes 10996
DRAM .bss size: 12552 bytes 12552
Used static DRAM: 23548 bytes ( 157188 available, 13.0% used) 23548 ( +0 available, +0 total)
Used static IRAM: 54145 bytes ( 76927 available, 41.3% used) 54145 ( +0 available, +0 total)
Flash code: 605331 bytes 603979 +1352
Flash rodata: 196788 bytes 187772 +9016
Total image size:~ 879812 bytes (.bin may be padded larger) 869444 +10368
```
* Initializes and allocates in the constructor (might throw) * Initializes and allocates in the constructor (might throw)
- easier code with exceptions ON, with exceptions OFF alloc/init failures are not treated as runtime error (program aborts) - easier code with exceptions ON, with exceptions OFF alloc/init failures are not treated as runtime error (program aborts)
- break down long initialization in constructor into more private methods - break down long initialization in constructor into more private methods
* Implements different devices using inheritance from `GenericModule`, which is the most general implementation of a common modem * Implements different devices using inheritance from `GenericModule`, which is the most general implementation of a common modem
- Internally uses templates with device specialization (modeled as `DCE<SpecificModule>`) which could be used as well for some special cases, - Internally uses templates with device specialization (modeled as `DCE<SpecificModule>`) which could be used as well for some special cases,
such as implantation of a minimal device (ModuleIf), add new AT commands (oOnly in compile time), or using the Module with DTE only (no DCE, no Netif) for sending AT commands without network such as implantation of a minimal device (ModuleIf), add new AT commands (oOnly in compile time), or using the Module with DTE only (no DCE, no Netif) for sending AT commands without network
@ -57,12 +26,11 @@ The diagram describes how the DCE class collaborates with DTE, PPP and the devic
Terminal is a class which can read or write data, and can handle callbacks when data are available. UART specialization Terminal is a class which can read or write data, and can handle callbacks when data are available. UART specialization
is provided implementing these method using the uart driver. is provided implementing these method using the uart driver.
![TerminalInheritance](Terminal_inheritance.png)
## CMUX terminal ## CMUX terminal
The below diagram depicts the idea of using CMUX terminal mode using the CMux class which is a terminal The below diagram depicts the idea of using CMUX terminal mode using the CMuxInstance class which is a terminal
(it implements the basic read/write methods) interfacing arbitrary number of virtual terminals, (it implements the basic read/write methods) interfacing arbitrary number of virtual terminals,
but at the same time it is also composed of another terminal, the real terminal, which is multiplexed. but at the same time it is also composed of CMux class, which consumes the original terminal and uses its read/write methods
to multiplex the terminal.
![CMUX Terminal](CMux_collaboration.png) ![CMUX Terminal](CMux_collaboration.png)

View File

@ -0,0 +1,85 @@
DCE Internal implementation
===========================
This chapter provides a detailed description of the classes and building blocks of the esp-modem component and their responsibilities.
The esp-modem actually implements the DCE class, which in turn aggregates these thee units:
- :ref:`DTE<dte_impl>` to communicate with the device on a specific Terminal interface such as UART.
- :ref:`Netif<netif_impl>` to provide the network connectivity
- :ref:`Module<module_impl>` to define the specific command library
------------
.. doxygengroup:: ESP_MODEM_DCE
:members:
.. _dte_impl:
DTE abstraction
---------------
DTE is a basic unit to talk to the module using a Terminal interface. It also implements and uses the CMUX to multiplex
terminals. Besides the DTE documentation, this section also refers to the
- :ref:`Terminal interface<term_impl>`
- :ref:`CMUX implementation<cmux_impl>`
------------
.. doxygengroup:: ESP_MODEM_DTE
:members:
.. _term_impl:
Terminal interface
^^^^^^^^^^^^^^^^^^
.. doxygengroup:: ESP_MODEM_TERMINAL
:members:
.. _cmux_impl:
CMUX implementation
^^^^^^^^^^^^^^^^^^^
.. doxygengroup:: ESP_MODEM_CMUX
:members:
.. _netif_impl:
Netif
-----
.. doxygengroup:: ESP_MODEM_NETIF
:members:
.. _module_impl:
Module abstraction
------------------
.. doxygengroup:: ESP_MODEM_MODULE
:members:
Command library
^^^^^^^^^^^^^^^
This is a namespace holding a library of typical AT commands used by supported devices.
Please refer to the :ref:`c_api` for the list of supported commands.
.. doxygengroup:: ESP_MODEM_DCE_COMMAND
:members:
Modem types
-----------
.. doxygengroup:: ESP_MODEM_TYPES
:members:

View File

@ -26,9 +26,6 @@ struct esp_modem_dce_config;
namespace esp_modem { namespace esp_modem {
class DTE; class DTE;
using dce_config = ::esp_modem_dce_config;
using dte_config = ::esp_modem_dte_config;
typedef struct esp_netif_obj esp_netif_t; typedef struct esp_netif_obj esp_netif_t;
@ -40,6 +37,9 @@ typedef struct esp_netif_obj esp_netif_t;
* @{ * @{
*/ */
using dce_config = ::esp_modem_dce_config;
using dte_config = ::esp_modem_dte_config;
/** /**
* @brief Create UART DTE * @brief Create UART DTE
* @param config DTE configuration * @param config DTE configuration
@ -52,7 +52,7 @@ std::shared_ptr<DTE> create_uart_dte(const dte_config *config);
/** /**
* @defgroup ESP_MODEM_INIT_DCE ESP_MODEM Initialization API for DCE * @defgroup ESP_MODEM_INIT_DCE ESP_MODEM Initialization API for DCE
* @brief Create DCE's * @brief ESP_MODEM Initialization API for DCE
*/ */
/** @addtogroup ESP_MODEM_INIT_DCE /** @addtogroup ESP_MODEM_INIT_DCE
* @{ * @{

View File

@ -49,6 +49,10 @@ enum class cmux_state {
*/ */
class CMuxInstance; 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
*/
class CMux { class CMux {
public: public:
explicit CMux(std::unique_ptr<Terminal> t, std::unique_ptr<uint8_t[]> b, size_t buff_size): explicit CMux(std::unique_ptr<Terminal> t, std::unique_ptr<uint8_t[]> b, size_t buff_size):
@ -77,6 +81,10 @@ private:
int instance; int instance;
}; };
/**
* @brief This represents a specific instance of a CMUX virtual terminal. This class also implements Terminal interface
* and as such could be used as a DTE's terminal.
*/
class CMuxInstance: public Terminal { class CMuxInstance: public Terminal {
public: public:
explicit CMuxInstance(std::shared_ptr<CMux> parent, int i): cmux(std::move(parent)), instance(i) {} explicit CMuxInstance(std::shared_ptr<CMux> parent, int i): cmux(std::move(parent)), instance(i) {}

View File

@ -21,6 +21,18 @@
namespace esp_modem { namespace esp_modem {
/**
* @defgroup ESP_MODEM_DCE
* @brief Definition of DCE abstraction
*/
/** @addtogroup ESP_MODEM_DCE
* @{
*/
/**
* @brief Helper class responsible for switching modes of the DCE's
*/
class DCE_Mode { class DCE_Mode {
public: public:
DCE_Mode(): mode(modem_mode::COMMAND_MODE) {} DCE_Mode(): mode(modem_mode::COMMAND_MODE) {}
@ -33,7 +45,10 @@ private:
}; };
/**
* @brief General DCE class templated on a specific module. It is responsible for all the necessary transactions
* related to switching modes and consequent synergy with aggregated objects of DTE, Netif and a specific Module
*/
template<class SpecificModule> template<class SpecificModule>
class DCE_T { class DCE_T {
static_assert(std::is_base_of<ModuleIf, SpecificModule>::value, "DCE must be instantiated with Module class only"); static_assert(std::is_base_of<ModuleIf, SpecificModule>::value, "DCE must be instantiated with Module class only");
@ -72,7 +87,10 @@ protected:
DCE_Mode mode; DCE_Mode mode;
}; };
/**
* @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.
*/
class DCE: public DCE_T<GenericModule> { class DCE: public DCE_T<GenericModule> {
public: public:
@ -90,6 +108,10 @@ public:
}; };
/**
* @}
*/
} // esp_modem } // esp_modem
#endif // _ESP_MODEM_DCE_HPP_ #endif // _ESP_MODEM_DCE_HPP_

View File

@ -15,10 +15,24 @@
#ifndef _ESP_MODEM_DCE_FACTORY_HPP_ #ifndef _ESP_MODEM_DCE_FACTORY_HPP_
#define _ESP_MODEM_DCE_FACTORY_HPP_ #define _ESP_MODEM_DCE_FACTORY_HPP_
/**
* @defgroup ESP_MODEM_DCE_FACTORY
* @brief DCE modem factory
*/
namespace esp_modem::dce_factory { namespace esp_modem::dce_factory {
using config = ::esp_modem_dce_config; using config = ::esp_modem_dce_config;
/** @addtogroup ESP_MODEM_DCE_FACTORY
* @{
*/
/**
* @brief Helper class for creating a uder define pointer in a specific way, either as a plain pointer, shared_ptr or unique_ptr
*/
class FactoryHelper { class FactoryHelper {
public: public:
static std::unique_ptr<PdpContext> create_pdp_context(std::string &apn); static std::unique_ptr<PdpContext> create_pdp_context(std::string &apn);
@ -43,6 +57,9 @@ public:
}; };
/**
* @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
*/
template<typename Module> template<typename Module>
class Builder { class Builder {
static_assert(std::is_base_of<ModuleIf, Module>::value, "Builder must be used only for Module classes"); static_assert(std::is_base_of<ModuleIf, Module>::value, "Builder must be used only for Module classes");
@ -87,23 +104,46 @@ private:
esp_netif_t *netif; esp_netif_t *netif;
}; };
/**
* @brief Specific modem choice when creating by the Factory
*/
enum class Modem { enum class Modem {
SIM800, GenericModule, /*!< Default generic module with the most common commands */
SIM7600, SIM800, /*!< Derived from the GenericModule with specifics applied to SIM800 model */
BG96, SIM7600, /*!< Derived from the GenericModule, specifics applied to SIM7600 model */
MinModule BG96, /*!< Derived from the GenericModule, specifics applied to BG69 model */
}; };
/**
* @brief Factory class for creating virtual DCE objects based on the configuration of the supplied module.
* This could also be used to create a custom module or a DCE_T<module>, provided user app derives from this factory.
*/
class Factory { class Factory {
public: public:
explicit Factory(Modem modem): m(modem) {} explicit Factory(Modem modem): m(modem) {}
/**
* @brief Create a default unique_ptr DCE in a specific way (from the module)
* @tparam Module Specific Module used in this DCE
* @tparam Args Arguments to the builder, i.e. constructor of esp_modem::DCE_T class
* @param cfg DCE configuration structure ::esp_modem_dte_config
* @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> template <typename Module, typename ...Args>
static std::unique_ptr<DCE> build_unique(const config *cfg, Args&&... 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<Module, DCE, std::unique_ptr<DCE>>(cfg, std::forward<Args>(args)...);
} }
/**
* @brief Create a DCE
* @tparam Module Specific Module used in this DCE
* @tparam Args Arguments to the builder, i.e. constructor of esp_modem::DCE_T class
* @param cfg DCE configuration structure ::esp_modem_dte_config
* @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> template <typename Module, typename ...Args>
static DCE* build(const config *cfg, Args&&... args) static DCE* build(const config *cfg, Args&&... args)
{ {
@ -128,12 +168,21 @@ public:
return build_shared_module<SIM7600>(cfg, std::forward<Args>(args)...); return build_shared_module<SIM7600>(cfg, std::forward<Args>(args)...);
case Modem::BG96: case Modem::BG96:
return build_shared_module<BG96>(cfg, std::forward<Args>(args)...); return build_shared_module<BG96>(cfg, std::forward<Args>(args)...);
case Modem::MinModule: case Modem::GenericModule:
return build_shared_module<GenericModule>(cfg, std::forward<Args>(args)...);
default:
break; break;
} }
return nullptr; return nullptr;
} }
/**
* @brief Create a default unique_ptr DCE generically, with the chosen module derived from the GenericModule
* @tparam Args Arguments to the builder, i.e. constructor of esp_modem::DCE_T class
* @param cfg DCE configuration structure ::esp_modem_dte_config
* @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 ...Args> 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)
{ {
@ -144,7 +193,9 @@ public:
return build_unique<SIM7600>(cfg, std::forward<Args>(args)...); return build_unique<SIM7600>(cfg, std::forward<Args>(args)...);
case Modem::BG96: case Modem::BG96:
return build_unique<BG96>(cfg, std::forward<Args>(args)...); return build_unique<BG96>(cfg, std::forward<Args>(args)...);
case Modem::MinModule: case Modem::GenericModule:
return build_unique<GenericModule>(cfg, std::forward<Args>(args)...);
default:
break; break;
} }
return nullptr; return nullptr;
@ -169,6 +220,11 @@ protected:
} }
}; };
/**
* @}
*/
} // namespace esp_modem::dce_factory } // namespace esp_modem::dce_factory
#endif // _ESP_MODEM_DCE_FACTORY_HPP_ #endif // _ESP_MODEM_DCE_FACTORY_HPP_

View File

@ -24,10 +24,23 @@
namespace esp_modem { namespace esp_modem {
/**
* @defgroup ESP_MODEM_MODULE
* @brief Definition of modules representing specific modem devices
*/
/** @addtogroup ESP_MODEM_MODULE
* @{
*/
enum class command_result; enum class command_result;
class DTE; class DTE;
struct PdpContext; struct PdpContext;
/**
* @brief This is a basic building block for custom modules as well as for the supported modules in the esp-modem component
* It derives from the ModuleIf.
*/
class GenericModule: public ModuleIf { class GenericModule: public ModuleIf {
public: public:
explicit GenericModule(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp): explicit GenericModule(std::shared_ptr<DTE> dte, std::unique_ptr<PdpContext> pdp):
@ -72,24 +85,37 @@ protected:
}; };
// Definitions of other modules // Definitions of other modules
/**
* @brief Specific definition of the SIM7600 module
*/
class SIM7600: public GenericModule { class SIM7600: public GenericModule {
using GenericModule::GenericModule; using GenericModule::GenericModule;
public: public:
command_result get_module_name(std::string& name) override; command_result get_module_name(std::string& name) override;
}; };
/**
* @brief Specific definition of the SIM800 module
*/
class SIM800: public GenericModule { class SIM800: public GenericModule {
using GenericModule::GenericModule; using GenericModule::GenericModule;
public: public:
command_result get_module_name(std::string& name) override; command_result get_module_name(std::string& name) override;
}; };
/**
* @brief Specific definition of the BG96 module
*/
class BG96: public GenericModule { class BG96: public GenericModule {
using GenericModule::GenericModule; using GenericModule::GenericModule;
public: public:
command_result get_module_name(std::string& name) override; command_result get_module_name(std::string& name) override;
}; };
/**
* @}
*/
} // namespace esp_modem } // namespace esp_modem

View File

@ -26,14 +26,37 @@
namespace esp_modem { namespace esp_modem {
/**
* @defgroup ESP_MODEM_DTE
* @brief Definition of DTE and related classes
*/
/** @addtogroup ESP_MODEM_DTE
* @{
*/
/**
* DTE (Data Terminal Equipment) class
*/
class DTE : public CommandableIf { class DTE : public CommandableIf {
public: public:
explicit DTE(std::unique_ptr<Terminal> t); explicit DTE(std::unique_ptr<Terminal> t);
~DTE() = default; ~DTE() = default;
/**
* @brief Writing to the underlying terminal
* @param data Data pointer to write
* @param len Data len to write
* @return number of bytes written
*/
int write(uint8_t *data, size_t len) { return term->write(data, len); } int write(uint8_t *data, size_t len) { return term->write(data, len); }
/**
* @brief Reading from the underlying terminal
* @param d Returning the data pointer of the received payload
* @param len Length of the data payload
* @return number of bytes read
*/
int read(uint8_t **d, size_t len) { int read(uint8_t **d, size_t len) {
auto data_to_read = std::min(len, buffer_size); auto data_to_read = std::min(len, buffer_size);
auto data = buffer.get(); auto data = buffer.get();
@ -92,6 +115,9 @@ private:
std::function<bool(uint8_t *data, size_t len)> on_data; std::function<bool(uint8_t *data, size_t len)> on_data;
}; };
/**
* @}
*/
} // namespace esp_modem } // namespace esp_modem

View File

@ -30,16 +30,37 @@ struct ppp_netif_driver {
Netif *ppp; Netif *ppp;
}; };
/**
* @defgroup ESP_MODEM_NETIF
* @brief Network interface layer of the esp-modem
*/
/** @addtogroup ESP_MODEM_NETIF
* @{
*/
/**
* @brief Network interface class responsible to glue the esp-netif to the modem's DCE
*/
class Netif { class Netif {
public: public:
explicit Netif(std::shared_ptr<DTE> e, esp_netif_t *netif); explicit Netif(std::shared_ptr<DTE> e, esp_netif_t *netif);
~Netif(); ~Netif();
/**
* @brief Start the network interface
*/
void start(); void start();
/**
* @brief Blocks until the network interface closes
*/
void wait_until_ppp_exits(); void wait_until_ppp_exits();
/**
* @brief Stop the network interface
*/
void stop(); void stop();
private: private:
@ -59,6 +80,10 @@ private:
static const size_t PPP_EXIT = signal_group::bit1; static const size_t PPP_EXIT = signal_group::bit1;
}; };
/**
* @}
*/
} // namespace esp_modem } // namespace esp_modem
#endif // _ESP_MODEM_NETIF_HPP #endif // _ESP_MODEM_NETIF_HPP

View File

@ -26,37 +26,64 @@
namespace esp_modem { namespace esp_modem {
/**
* @defgroup ESP_MODEM_TERMINAL
* @brief Definition of an abstract terminal to be attached to DTE class
*/
/** @addtogroup ESP_MODEM_TERMINAL
* @{
*/
/**
* @brief Terminal errors
*/
enum class terminal_error { enum class terminal_error {
BUFFER_OVERFLOW, BUFFER_OVERFLOW,
CHECKSUM_ERROR, CHECKSUM_ERROR,
UNEXPECTED_CONTROL_FLOW, UNEXPECTED_CONTROL_FLOW,
}; };
/**
* @brief Terminal interface. All communication interfaces must comply this interface in order to be used as a DTE
*/
class Terminal { class Terminal {
public: public:
virtual ~Terminal() = default; virtual ~Terminal() = default;
// virtual void set_data_cb(std::function<bool(size_t len)> f) { on_data = std::move(f); }
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_data = std::move(f); }
/**
* @brief Writes data to the terminal
* @param data Data pointer
* @param len Data len
* @return length of data written
*/
virtual int write(uint8_t *data, size_t len) = 0; virtual int write(uint8_t *data, size_t len) = 0;
/**
* @brief Read from the terminal. This function doesn't block, but return all available data.
* @param data Data pointer to store the read payload
* @param len Maximum data len to read
* @return length of data actually read
*/
virtual int read(uint8_t *data, size_t len) = 0; virtual int read(uint8_t *data, size_t len) = 0;
virtual void start() = 0; virtual void start() = 0;
virtual void stop() = 0; virtual void stop() = 0;
virtual size_t max_virtual_terms() { return 1; }
protected: protected:
// std::function<bool(size_t len)> on_data;
std::function<bool(uint8_t *data, size_t len)> on_data; std::function<bool(uint8_t *data, size_t len)> on_data;
std::function<void(terminal_error)> on_error; std::function<void(terminal_error)> on_error;
}; };
/**
* @}
*/
} // namespace esp_modem } // namespace esp_modem
#endif // _ESP_MODEM_TERMINAL_HPP_ #endif // _ESP_MODEM_TERMINAL_HPP_

View File

@ -22,21 +22,40 @@
namespace esp_modem { namespace esp_modem {
/**
* @defgroup ESP_MODEM_TYPES
* @brief Basic type definitions used in esp-modem
*/
/** @addtogroup ESP_MODEM_TYPES
* @{
*/
/**
* @brief Modem working mode
*/
enum class modem_mode { enum class modem_mode {
UNDEF, UNDEF,
COMMAND_MODE, COMMAND_MODE, /*!< Command mode -- the modem is supposed to send AT commands in this mode */
DATA_MODE, DATA_MODE, /*!< Data mode -- the modem communicates with network interface on PPP protocol */
CMUX_MODE CMUX_MODE /*!< CMUX (Multiplex mode) -- Simplified CMUX mode, which creates two virtual terminals,
* assigning one solely to command interface and the other to the data mode */
}; };
/**
* @brief Module command result
*/
enum class command_result { enum class command_result {
OK, OK, /*!< The command completed successfully */
FAIL, FAIL, /*!< The command explicitly failed */
TIMEOUT TIMEOUT /*!< The device didn't respond in the specified timeline */
}; };
typedef std::function<command_result(uint8_t *data, size_t len)> got_line_cb; typedef std::function<command_result(uint8_t *data, size_t len)> got_line_cb;
/**
* @brief PDP context used for configuring and setting the data mode up
*/
struct PdpContext { struct PdpContext {
explicit PdpContext(std::string apn) : apn(std::move(apn)) {} explicit PdpContext(std::string apn) : apn(std::move(apn)) {}
size_t context_id = 1; size_t context_id = 1;
@ -44,18 +63,44 @@ struct PdpContext {
std::string apn; std::string apn;
}; };
/**
* @brief Interface for classes eligible to send AT commands (Modules, DCEs, DTEs)
*/
class CommandableIf { class CommandableIf {
public: public:
/**
* @brief Sends custom AT command
* @param command Command to be sent
* @param got_line callback if a line received
* @param time_ms timeout in milliseconds
* @return OK, FAIL or TIMEOUT
*/
virtual command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms) = 0; virtual command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms) = 0;
}; };
/**
* @brief Interface for classes implementing a module for the modem
*/
class ModuleIf { class ModuleIf {
public: public:
/**
* @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; virtual bool setup_data_mode() = 0;
/**
* @brief Sets the operation mode
* @param mode Desired mode
* @return true on success
*/
virtual bool set_mode(modem_mode mode) = 0; virtual bool set_mode(modem_mode mode) = 0;
}; };
/**
* @}
*/
} // namespace esp_modem } // namespace esp_modem
#endif // _ESP_MODEM_TYPES_HPP_ #endif // _ESP_MODEM_TYPES_HPP_

View File

@ -17,6 +17,15 @@
#include "driver/uart.h" #include "driver/uart.h"
#include "esp_modem_dce_config.h" #include "esp_modem_dce_config.h"
/**
* @defgroup ESP_MODEM_CONFIG
* @brief Configuration structures for DTE and DCE
*/
/** @addtogroup ESP_MODEM_CONFIG
* @{
*/
/** /**
* @brief Modem flow control type * @brief Modem flow control type
* *
@ -27,6 +36,10 @@ typedef enum {
ESP_MODEM_FLOW_CONTROL_HW ESP_MODEM_FLOW_CONTROL_HW
} esp_modem_flow_ctrl_t; } esp_modem_flow_ctrl_t;
/**
* @brief DTE configuration structure
*
*/
struct esp_modem_dte_config { struct esp_modem_dte_config {
uart_port_t port_num; /*!< UART port number */ uart_port_t port_num; /*!< UART port number */
uart_word_length_t data_bits; /*!< Data bits of UART */ uart_word_length_t data_bits; /*!< Data bits of UART */
@ -74,4 +87,8 @@ struct esp_modem_dte_config {
typedef struct esp_modem_dte_config esp_modem_dte_config_t; typedef struct esp_modem_dte_config esp_modem_dte_config_t;
/**
* @}
*/
#endif // _ESP_MODEM_CONFIG_H_ #endif // _ESP_MODEM_CONFIG_H_

View File

@ -15,10 +15,14 @@
#ifndef _ESP_MODEM_DCE_CONFIG_H_ #ifndef _ESP_MODEM_DCE_CONFIG_H_
#define _ESP_MODEM_DCE_CONFIG_H_ #define _ESP_MODEM_DCE_CONFIG_H_
struct esp_modem_dce_config { /** @addtogroup ESP_MODEM_CONFIG
const char* apn; * @{
}; */
/**
* @brief ESP Modem DCE Default Configuration
*
*/
#define ESP_MODEM_DCE_DEFAULT_CONFIG(APN) \ #define ESP_MODEM_DCE_DEFAULT_CONFIG(APN) \
{ \ { \
.apn = APN \ .apn = APN \
@ -26,4 +30,16 @@ struct esp_modem_dce_config {
typedef struct esp_modem_dce_config esp_modem_dce_config_t; typedef struct esp_modem_dce_config esp_modem_dce_config_t;
/**
* @brief DCE configuration structure
*/
struct esp_modem_dce_config {
const char* apn; /*!< APN: Logical name of the Access point */
};
/**
* @}
*/
#endif // _ESP_MODEM_DCE_CONFIG_H_ #endif // _ESP_MODEM_DCE_CONFIG_H_

View File

@ -132,17 +132,19 @@ ESP_MODEM_DECLARE_DCE_COMMAND(get_signal_quality, command_result, 2, MUX_ARG, IN
#ifdef GENERATE_DOCS #ifdef GENERATE_DOCS
// cat ../include/generate/esp_modem_command_declare.inc | clang++ -E -P -CC -xc++ -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p' // cat ../include/generate/esp_modem_command_declare.inc | clang++ -E -P -CC -xc++ -I../include -DGENERATE_DOCS - | sed -n '1,/DCE command documentation/!p'
// 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 -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
// --- DCE command documentation starts here --- // --- DCE command documentation starts here ---
#ifdef __cplusplus #ifdef __cplusplus
class DCE: public DCE_T<GenericModule> { class esp_modem::DCE: public DCE_T<GenericModule> {
public: public:
using DCE_T<GenericModule>::DCE_T; using DCE_T<GenericModule>::DCE_T;
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, TEMPLATE_ARG, MUX_ARG, ...) return_type name (__VA_ARGS__); #define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, TEMPLATE_ARG, MUX_ARG, ...) return_type name (__VA_ARGS__);
#elif defined(GENERATE_RST_LINKS)
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, TEMPLATE_ARG, MUX_ARG, ...) NL- :cpp:func:`esp_modem::DCE::name`
#else #else
#define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, TEMPLATE_ARG, MUX_ARG, ...) return_type esp_modem_ ## name (__VA_ARGS__); #define ESP_MODEM_DECLARE_DCE_COMMAND(name, return_type, TEMPLATE_ARG, MUX_ARG, ...) return_type esp_modem_ ## name (__VA_ARGS__);
#endif #endif
DECLARE_ALL_COMMAND_APIS() DECLARE_ALL_COMMAND_APIS()
#ifdef __cplusplus #ifdef __cplusplus