|
| 1 | +Customization |
| 2 | +============= |
| 3 | + |
| 4 | +This chapter covers how to customize ESP-MODEM for your specific requirements by creating custom modules and adding new commands. |
| 5 | + |
| 6 | +Custom Module Development |
| 7 | +------------------------- |
| 8 | + |
| 9 | +For most customization needs, you don't need development mode. Instead, you can create custom modules that inherit from existing ESP-MODEM classes. |
| 10 | + |
| 11 | +Creating Custom Modules |
| 12 | +~~~~~~~~~~~~~~~~~~~~~~~ |
| 13 | + |
| 14 | +The recommended approach for adding support for new modem modules or custom commands is to create a custom module class. This approach: |
| 15 | + |
| 16 | +- **Doesn't require development mode** |
| 17 | +- **Keeps your changes separate** from the core library |
| 18 | +- **Allows easy updates** of the ESP-MODEM library |
| 19 | +- **Provides full flexibility** for custom commands |
| 20 | + |
| 21 | +Basic Custom Module Example |
| 22 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 23 | + |
| 24 | +Here's a simple example of creating a custom module: |
| 25 | + |
| 26 | +.. code-block:: cpp |
| 27 | +
|
| 28 | + #include "cxx_include/esp_modem_api.hpp" |
| 29 | + #include "cxx_include/esp_modem_command_library_utils.hpp" |
| 30 | +
|
| 31 | + class MyCustomModule: public GenericModule { |
| 32 | + using GenericModule::GenericModule; |
| 33 | +
|
| 34 | + public: |
| 35 | + // Add a new command |
| 36 | + command_result get_custom_info(std::string &info) { |
| 37 | + return esp_modem::dce_commands::generic_get_string( |
| 38 | + dte.get(), "AT+CUSTOM?\r", info); |
| 39 | + } |
| 40 | +
|
| 41 | + // Override an existing command |
| 42 | + command_result get_signal_quality(int &rssi, int &ber) override { |
| 43 | + // Custom implementation |
| 44 | + return esp_modem::dce_commands::generic_get_string( |
| 45 | + dte.get(), "AT+CSQ\r", rssi, ber); |
| 46 | + } |
| 47 | + }; |
| 48 | +
|
| 49 | +Using Custom Modules with C++ API |
| 50 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 51 | + |
| 52 | +With the C++ API, you can use your custom module directly: |
| 53 | + |
| 54 | +.. code-block:: cpp |
| 55 | +
|
| 56 | + // Create DCE with custom module |
| 57 | + auto dce = dce_factory::Factory::create_unique_dce_from<MyCustomModule>( |
| 58 | + dce_config, std::move(dte), netif); |
| 59 | +
|
| 60 | + // Use custom commands |
| 61 | + std::string info; |
| 62 | + auto result = dce->get_custom_info(info); |
| 63 | +
|
| 64 | +Using Custom Modules with C API |
| 65 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 66 | + |
| 67 | +To use custom modules with the C API, you need to: |
| 68 | + |
| 69 | +1. **Enable custom module support** in Kconfig: |
| 70 | + |
| 71 | + .. code-block:: bash |
| 72 | +
|
| 73 | + idf.py menuconfig |
| 74 | + # Navigate to: Component config → ESP-MODEM |
| 75 | + # Enable: "Add support for custom module in C-API" |
| 76 | +
|
| 77 | +2. **Create a custom module header** (e.g., ``custom_module.hpp``) in your main component |
| 78 | + |
| 79 | +3. **Implement the required functions**: |
| 80 | + |
| 81 | + .. code-block:: cpp |
| 82 | +
|
| 83 | + // Create custom DCE function |
| 84 | + DCE *esp_modem_create_custom_dce( |
| 85 | + const esp_modem_dce_config_t *dce_config, |
| 86 | + std::shared_ptr<DTE> dte, |
| 87 | + esp_netif_t *netif) { |
| 88 | + return dce_factory::Factory::create_unique_dce_from<MyCustomModule, DCE *>( |
| 89 | + dce_config, std::move(dte), netif); |
| 90 | + } |
| 91 | +
|
| 92 | + // Add C API wrappers for custom commands |
| 93 | + extern "C" esp_err_t esp_modem_get_custom_info(esp_modem_dce_t *dce_wrap, char *info) { |
| 94 | + if (dce_wrap == nullptr || dce_wrap->dce == nullptr) { |
| 95 | + return ESP_ERR_INVALID_ARG; |
| 96 | + } |
| 97 | + std::string info_str{CONFIG_ESP_MODEM_C_API_STR_MAX}; |
| 98 | + auto ret = command_response_to_esp_err( |
| 99 | + static_cast<MyCustomModule *>(dce_wrap->dce->get_module())->get_custom_info(info_str)); |
| 100 | + if (ret == ESP_OK && !info_str.empty()) { |
| 101 | + strlcpy(info, info_str.c_str(), CONFIG_ESP_MODEM_C_API_STR_MAX); |
| 102 | + } |
| 103 | + return ret; |
| 104 | + } |
| 105 | +
|
| 106 | +4. **Use the custom commands** in your C code: |
| 107 | + |
| 108 | + .. code-block:: c |
| 109 | +
|
| 110 | + char info[128]; |
| 111 | + esp_err_t ret = esp_modem_get_custom_info(dce, info); |
| 112 | +
|
| 113 | +Complete Example |
| 114 | +~~~~~~~~~~~~~~~~ |
| 115 | + |
| 116 | +See the ``examples/pppos_client`` example for a complete demonstration of custom module development. This example shows: |
| 117 | + |
| 118 | +- Creating a custom module that inherits from ``GenericModule`` |
| 119 | +- Adding new commands (``get_time()``) |
| 120 | +- Overriding existing commands (``get_signal_quality()``) |
| 121 | +- Integration with both C++ and C APIs |
| 122 | + |
| 123 | +Available Base Classes |
| 124 | +---------------------- |
| 125 | + |
| 126 | +You can inherit from several base classes depending on your needs: |
| 127 | + |
| 128 | +**GenericModule** |
| 129 | + The most general implementation of a common modem. Use this when: |
| 130 | + - Your modem supports most standard AT commands |
| 131 | + - You need to add a few custom commands |
| 132 | + - You want to override some existing commands |
| 133 | + |
| 134 | +**Specific Module Classes** |
| 135 | + Inherit from existing module classes (e.g., ``SIM800``, ``BG96``, ``SIM7600``) when: |
| 136 | + - Your modem is very similar to an existing one |
| 137 | + - You only need minor modifications |
| 138 | + - You want to leverage existing device-specific optimizations |
| 139 | + |
| 140 | +**ModuleIf** |
| 141 | + Use this minimal interface when: |
| 142 | + - You only need basic AT command functionality |
| 143 | + - You don't need network interface features |
| 144 | + - You want to implement a custom DTE without DCE |
| 145 | + |
| 146 | +Command Utilities |
| 147 | +----------------- |
| 148 | + |
| 149 | +ESP-MODEM provides utility functions to help implement custom commands: |
| 150 | + |
| 151 | +**Generic Command Helpers** |
| 152 | + - ``generic_get_string()`` - Parse string responses |
| 153 | + - ``generic_get_int()`` - Parse integer responses |
| 154 | + - ``generic_set_string()`` - Send string commands |
| 155 | + - ``generic_set_int()`` - Send integer commands |
| 156 | + |
| 157 | +**Response Parsing** |
| 158 | + - ``get_number_from_string()`` - Extract numbers from responses |
| 159 | + - ``get_string_from_response()`` - Extract strings from responses |
| 160 | + - ``get_urc()`` - Handle unsolicited result codes |
| 161 | + |
| 162 | +Example Usage: |
| 163 | +.. code-block:: cpp |
| 164 | +
|
| 165 | + // Get a string value |
| 166 | + command_result get_imei(std::string &imei) { |
| 167 | + return esp_modem::dce_commands::generic_get_string( |
| 168 | + dte.get(), "AT+CGSN\r", imei); |
| 169 | + } |
| 170 | +
|
| 171 | + // Get an integer value |
| 172 | + command_result get_signal_strength(int &rssi) { |
| 173 | + return esp_modem::dce_commands::generic_get_int( |
| 174 | + dte.get(), "AT+CSQ\r", rssi); |
| 175 | + } |
| 176 | +
|
| 177 | +Best Practices |
| 178 | +-------------- |
| 179 | + |
| 180 | +**For Application Developers:** |
| 181 | +- Use production mode for better IDE support and faster builds |
| 182 | +- Create custom modules for new modem support |
| 183 | +- Inherit from ``GenericModule`` or other existing modules |
| 184 | +- Keep customizations in your project, not in the ESP-MODEM library |
| 185 | + |
| 186 | +**Module Design:** |
| 187 | +- Choose the most appropriate base class for your needs |
| 188 | +- Override only the commands you need to modify |
| 189 | +- Use the provided utility functions for common operations |
| 190 | +- Follow the existing command naming conventions |
| 191 | + |
| 192 | +**Testing:** |
| 193 | +- Test your custom module with real hardware |
| 194 | +- Verify compatibility with existing ESP-MODEM features |
| 195 | +- Test both C++ and C API usage if applicable |
| 196 | +- Consider edge cases and error handling |
| 197 | + |
| 198 | +**Documentation:** |
| 199 | +- Document your custom commands clearly |
| 200 | +- Provide usage examples |
| 201 | +- Explain any device-specific requirements |
| 202 | +- Note any limitations or known issues |
0 commit comments