Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/esp_modem/en/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,41 @@ Component Kconfig
Compile-time configuration is provided using menuconfig. Please check
the description for the CMUX mode configuration options.

Development Mode
~~~~~~~~~~~~~~~~

ESP-MODEM supports two different modes for handling AT command definitions:

**Production Mode (Default)**
Uses pre-generated headers and sources with common AT commands from the ``command/`` directory.
This mode provides better IDE navigation and code completion, making it ideal for:

- Application development using existing AT commands
- Better code navigation and IntelliSense support
- Faster compilation times
- Stable, tested command implementations

**Development Mode**
Uses in-place macro expansion with AT commands from the ``generate/`` directory.
This mode is designed for ESP-MODEM library developers who need to:

- Modify or add new AT command definitions in ``esp_modem_command_declare.inc``
- Work directly with the source definitions of AT commands
- Debug command implementations
- Contribute to the core ESP-MODEM library development

.. note::
For adding support for new modem modules, you typically don't need development mode.
Instead, create a custom module class inheriting from ``GenericModule`` and add your
commands directly in your project's headers/sources. See the ``pppos_client`` example
for a demonstration of this approach.

To enable development mode, set ``CONFIG_ESP_MODEM_ENABLE_DEVELOPMENT_MODE=y`` in your project configuration.

.. note::
Development mode requires the C preprocessor to expand command definitions at compile time,
which may result in longer compilation times and larger binary sizes compared to production mode.

Runtime configuration
~~~~~~~~~~~~~~~~~~~~~

Expand Down
202 changes: 202 additions & 0 deletions docs/esp_modem/en/customization.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
Customization
=============

This chapter covers how to customize ESP-MODEM for your specific requirements by creating custom modules and adding new commands.

Custom Module Development
-------------------------

For most customization needs, you don't need development mode. Instead, you can create custom modules that inherit from existing ESP-MODEM classes.

Creating Custom Modules
~~~~~~~~~~~~~~~~~~~~~~~

The recommended approach for adding support for new modem modules or custom commands is to create a custom module class. This approach:

- **Doesn't require development mode**
- **Keeps your changes separate** from the core library
- **Allows easy updates** of the ESP-MODEM library
- **Provides full flexibility** for custom commands

Basic Custom Module Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here's a simple example of creating a custom module:

.. code-block:: cpp

#include "cxx_include/esp_modem_api.hpp"
#include "cxx_include/esp_modem_command_library_utils.hpp"

class MyCustomModule: public GenericModule {
using GenericModule::GenericModule;

public:
// Add a new command
command_result get_custom_info(std::string &info) {
return esp_modem::dce_commands::generic_get_string(
dte.get(), "AT+CUSTOM?\r", info);
}

// Override an existing command
command_result get_signal_quality(int &rssi, int &ber) override {
// Custom implementation
return esp_modem::dce_commands::generic_get_string(
dte.get(), "AT+CSQ\r", rssi, ber);
}
};

Using Custom Modules with C++ API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

With the C++ API, you can use your custom module directly:

.. code-block:: cpp

// Create DCE with custom module
auto dce = dce_factory::Factory::create_unique_dce_from<MyCustomModule>(
dce_config, std::move(dte), netif);

// Use custom commands
std::string info;
auto result = dce->get_custom_info(info);

Using Custom Modules with C API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To use custom modules with the C API, you need to:

1. **Enable custom module support** in Kconfig:

.. code-block:: bash

idf.py menuconfig
# Navigate to: Component config → ESP-MODEM
# Enable: "Add support for custom module in C-API"

2. **Create a custom module header** (e.g., ``custom_module.hpp``) in your main component

3. **Implement the required functions**:

.. code-block:: cpp

// Create custom DCE function
DCE *esp_modem_create_custom_dce(
const esp_modem_dce_config_t *dce_config,
std::shared_ptr<DTE> dte,
esp_netif_t *netif) {
return dce_factory::Factory::create_unique_dce_from<MyCustomModule, DCE *>(
dce_config, std::move(dte), netif);
}

// Add C API wrappers for custom commands
extern "C" esp_err_t esp_modem_get_custom_info(esp_modem_dce_t *dce_wrap, char *info) {
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
return ESP_ERR_INVALID_ARG;
}
std::string info_str{CONFIG_ESP_MODEM_C_API_STR_MAX};
auto ret = command_response_to_esp_err(
static_cast<MyCustomModule *>(dce_wrap->dce->get_module())->get_custom_info(info_str));
if (ret == ESP_OK && !info_str.empty()) {
strlcpy(info, info_str.c_str(), CONFIG_ESP_MODEM_C_API_STR_MAX);
}
return ret;
}

4. **Use the custom commands** in your C code:

.. code-block:: c

char info[128];
esp_err_t ret = esp_modem_get_custom_info(dce, info);

Complete Example
~~~~~~~~~~~~~~~~

See the ``examples/pppos_client`` example for a complete demonstration of custom module development. This example shows:

- Creating a custom module that inherits from ``GenericModule``
- Adding new commands (``get_time()``)
- Overriding existing commands (``get_signal_quality()``)
- Integration with both C++ and C APIs

Available Base Classes
----------------------

You can inherit from several base classes depending on your needs:

**GenericModule**
The most general implementation of a common modem. Use this when:
- Your modem supports most standard AT commands
- You need to add a few custom commands
- You want to override some existing commands

**Specific Module Classes**
Inherit from existing module classes (e.g., ``SIM800``, ``BG96``, ``SIM7600``) when:
- Your modem is very similar to an existing one
- You only need minor modifications
- You want to leverage existing device-specific optimizations

**ModuleIf**
Use this minimal interface when:
- You only need basic AT command functionality
- You don't need network interface features
- You want to implement a custom DTE without DCE

Command Utilities
-----------------

ESP-MODEM provides utility functions to help implement custom commands:

**Generic Command Helpers**
- ``generic_get_string()`` - Parse string responses
- ``generic_get_int()`` - Parse integer responses
- ``generic_set_string()`` - Send string commands
- ``generic_set_int()`` - Send integer commands

**Response Parsing**
- ``get_number_from_string()`` - Extract numbers from responses
- ``get_string_from_response()`` - Extract strings from responses
- ``get_urc()`` - Handle unsolicited result codes

Example Usage:
.. code-block:: cpp

// Get a string value
command_result get_imei(std::string &imei) {
return esp_modem::dce_commands::generic_get_string(
dte.get(), "AT+CGSN\r", imei);
}

// Get an integer value
command_result get_signal_strength(int &rssi) {
return esp_modem::dce_commands::generic_get_int(
dte.get(), "AT+CSQ\r", rssi);
}

Best Practices
--------------

**For Application Developers:**
- Use production mode for better IDE support and faster builds
- Create custom modules for new modem support
- Inherit from ``GenericModule`` or other existing modules
- Keep customizations in your project, not in the ESP-MODEM library

**Module Design:**
- Choose the most appropriate base class for your needs
- Override only the commands you need to modify
- Use the provided utility functions for common operations
- Follow the existing command naming conventions

**Testing:**
- Test your custom module with real hardware
- Verify compatibility with existing ESP-MODEM features
- Test both C++ and C API usage if applicable
- Consider edge cases and error handling

**Documentation:**
- Document your custom commands clearly
- Provide usage examples
- Explain any device-specific requirements
- Note any limitations or known issues
Loading
Loading