Skip to content

Commit cc40cc1

Browse files
authored
Merge pull request espressif#413 from david-cermak/feat/new_modem_cmd
Added support for implementing user defined modules in standard C-API
2 parents f50edd4 + 020b407 commit cc40cc1

File tree

11 files changed

+587
-444
lines changed

11 files changed

+587
-444
lines changed

components/esp_modem/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ set_target_properties(${COMPONENT_LIB} PROPERTIES
4242
CXX_EXTENSIONS ON
4343
)
4444

45+
if(CONFIG_ESP_MODEM_ADD_CUSTOM_MODULE)
46+
idf_component_optional_requires(PUBLIC main)
47+
endif()
4548

4649
if(${target} STREQUAL "linux")
4750
# This is needed for ESP_LOGx() macros, as integer formats differ on ESP32(..) and x64

components/esp_modem/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,22 @@ menu "esp-modem"
4545
to make the protocol more robust on noisy environments or when underlying
4646
transport gets corrupted often (for example by Rx buffer overflows)
4747

48+
config ESP_MODEM_ADD_CUSTOM_MODULE
49+
bool "Add support for custom module in C-API"
50+
default n
51+
help
52+
If enabled, we adapt the C-API to create a DCE from a user defined class
53+
54+
config ESP_MODEM_CUSTOM_MODULE_HEADER
55+
string "Header file name which defines custom DCE creation"
56+
depends on ESP_MODEM_ADD_CUSTOM_MODULE
57+
default "custom_module.hpp"
58+
help
59+
Name of the header file in the main component which implements esp_modem_create_custom_dce()
60+
called from C-API for creating esp_modem_dce object.
61+
This header provides definition of the custom module with some additional and/or updated commands
62+
and API. It also defines creation of DCE based on this custom module, typically calling:
63+
dce_factory::Factory::create_unique_dce_from<CustomModule, DCE*>(dce_config, std::move(dte), netif)
64+
Please refer to the pppos_client example for more details.
65+
4866
endmenu

components/esp_modem/examples/pppos_client/main/Kconfig.projbuild

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ menu "Example Configuration"
4848
bool "A7670"
4949
help
5050
A7670X is Multi-Band LTE-FDD/LTE-TDD/GSM/GPRS/EDGE module.
51+
52+
config EXAMPLE_MODEM_DEVICE_CUSTOM
53+
select ESP_MODEM_ADD_CUSTOM_MODULE
54+
bool "Custom device"
55+
help
56+
This demonstrates use of a custom device in C-API.
57+
5158
endchoice
5259

5360
config EXAMPLE_MODEM_PPP_APN
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
7+
#pragma once
8+
#include "cxx_include/esp_modem_api.hpp"
9+
#include "cxx_include/esp_modem_command_library_utils.hpp"
10+
11+
/**
12+
* @brief Definition of a custom module based on some already defined module
13+
* Here we use GenericModule, but you can use any kind of device
14+
* that is closer to your CustomModule.
15+
*/
16+
class SIM7600_WITH_TIME: public GenericModule {
17+
/**
18+
* @brief Need to reuse the constructors of our ancestor
19+
*/
20+
using GenericModule::GenericModule;
21+
public:
22+
/**
23+
* @brief New command that is not defined in the GenericModule
24+
*/
25+
command_result get_time(std::string &time)
26+
{
27+
return esp_modem::dce_commands::generic_get_string(dte.get(), "AT+CCLK?\r", time);
28+
}
29+
30+
/**
31+
* @brief This command is already defined in the GenericModule
32+
*
33+
* Here we just modify get_signal_quality() to return zeroes
34+
* for demonstration purpose only, since it's called within this example
35+
*/
36+
command_result get_signal_quality(int &rssi, int &ber) override
37+
{
38+
rssi = ber = 0;
39+
return esp_modem::command_result::OK;
40+
}
41+
42+
};
43+
44+
/**
45+
* @brief esp_modem_create_custom_dce() needs to be defined, as it is called in C-API wrapper when creating esp_modem_dce
46+
*
47+
* This uses public factory function for creating a common DCE with our CustomModule. Creating raw DCE pointer is only needed
48+
* for the C-API wrapper; C++API users would create DCE (any kind of smart pointer) directly with
49+
* Factory::create_unique_dce_from<CustomModule>(dce_config, std::move(dte), netif);
50+
*/
51+
DCE *esp_modem_create_custom_dce(const esp_modem_dce_config_t *dce_config, std::shared_ptr<DTE> dte, esp_netif_t *netif)
52+
{
53+
return dce_factory::Factory::create_unique_dce_from<SIM7600_WITH_TIME, DCE *>(dce_config, std::move(dte), netif);
54+
}
55+
56+
/**
57+
* @brief This API is only needed for extending standard C-API, since we added get_time() method to our CustomModule
58+
*
59+
* @note This header is included from esp_modem_c_api.cpp, so it could use ESP_MODEM_C_API_STR_MAX macro
60+
* indicating maximum C-API string size
61+
*
62+
* @note In order to access the newly added API get_time(), we have to static_cast<> the GenericModule from DCE
63+
* to our CustomModule.
64+
* Alternatively we could use the modem Factory to build our specific DCE_T<CustomModule>, but in that case
65+
* we couldn't use our C-API wrappers which expect DCE type, DCE_T<GenericModule> with lib commands (this alternative
66+
* is cleaner, but more suitable for C++ users)
67+
*/
68+
extern "C" esp_err_t esp_modem_get_time(esp_modem_dce_t *dce_wrap, char *p_time)
69+
{
70+
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
71+
return ESP_ERR_INVALID_ARG;
72+
}
73+
std::string time{ESP_MODEM_C_API_STR_MAX};
74+
auto ret = command_response_to_esp_err(static_cast<SIM7600_WITH_TIME *>(dce_wrap->dce->get_module())->get_time(time));
75+
if (ret == ESP_OK && !time.empty()) {
76+
strlcpy(p_time, time.c_str(), ESP_MODEM_C_API_STR_MAX);
77+
}
78+
return ret;
79+
}

components/esp_modem/examples/pppos_client/main/pppos_client_main.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ static const int CONNECT_BIT = BIT0;
3737
static const int GOT_DATA_BIT = BIT2;
3838
static const int USB_DISCONNECTED_BIT = BIT3; // Used only with USB DTE but we define it unconditionally, to avoid too many #ifdefs in the code
3939

40+
#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_CUSTOM
41+
esp_err_t esp_modem_get_time(esp_modem_dce_t *dce_wrap, char *p_time);
42+
#endif
43+
4044
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
4145
#include "esp_modem_usb_c_api.h"
4246
#include "esp_modem_usb_config.h"
@@ -192,6 +196,9 @@ void app_main(void)
192196
#elif CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600 == 1
193197
ESP_LOGI(TAG, "Initializing esp_modem for the SIM7600 module...");
194198
esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM7600, &dte_config, &dce_config, esp_netif);
199+
#elif CONFIG_EXAMPLE_MODEM_DEVICE_CUSTOM == 1
200+
ESP_LOGI(TAG, "Initializing esp_modem with custom module...");
201+
esp_modem_dce_t *dce = esp_modem_new_dev(ESP_MODEM_DCE_CUSTOM, &dte_config, &dce_config, esp_netif);
195202
#else
196203
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
197204
esp_modem_dce_t *dce = esp_modem_new(&dte_config, &dce_config, esp_netif);
@@ -258,6 +265,18 @@ void app_main(void)
258265
}
259266
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);
260267

268+
#ifdef CONFIG_EXAMPLE_MODEM_DEVICE_CUSTOM
269+
{
270+
char time[64];
271+
err = esp_modem_get_time(dce, time);
272+
if (err != ESP_OK) {
273+
ESP_LOGE(TAG, "esp_modem_get_time failed with %d %s", err, esp_err_to_name(err));
274+
return;
275+
}
276+
ESP_LOGI(TAG, "esp_modem_get_time: %s", time);
277+
}
278+
#endif
279+
261280
#if CONFIG_EXAMPLE_SEND_MSG
262281
if (esp_modem_sms_txt_mode(dce, true) != ESP_OK || esp_modem_sms_character_set(dce) != ESP_OK) {
263282
ESP_LOGE(TAG, "Setting text mode or GSM character set failed");

components/esp_modem/include/cxx_include/esp_modem_dce_factory.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -12,6 +12,7 @@
1212
* @brief DCE modem factory
1313
*/
1414

15+
#define esp_modem_create_dce_from dce_factory::Factory::create_unique_dce_from
1516

1617
namespace esp_modem::dce_factory {
1718

@@ -236,12 +237,12 @@ class Factory {
236237
return nullptr;
237238
}
238239

239-
template <typename T_Module>
240-
static std::unique_ptr<DCE> create_unique_dce_from(const esp_modem::dce_config *config,
241-
std::shared_ptr<esp_modem::DTE> dte,
242-
esp_netif_t *netif)
240+
template <typename T_Module, typename Ptr = std::unique_ptr<DCE>>
241+
static Ptr create_unique_dce_from(const esp_modem::dce_config *config,
242+
std::shared_ptr<esp_modem::DTE> dte,
243+
esp_netif_t *netif)
243244
{
244-
return build_generic_DCE<T_Module, DCE, std::unique_ptr<DCE>>(config, std::move(dte), netif);
245+
return build_generic_DCE<T_Module, DCE, Ptr>(config, std::move(dte), netif);
245246
}
246247

247248
private:

components/esp_modem/include/cxx_include/esp_modem_types.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class CommandableIf {
7676
* @param command Command to be sent
7777
* @param got_line callback if a line received
7878
* @param time_ms timeout in milliseconds
79+
* @param separator Character treated as a line separator, typically '\n'
7980
* @return OK, FAIL or TIMEOUT
8081
*/
8182
virtual command_result command(const std::string &command, got_line_cb got_line, uint32_t time_ms, const char separator) = 0;

components/esp_modem/include/esp_modem_c_api_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ typedef enum esp_modem_dce_device {
5353
ESP_MODEM_DCE_SIM7000,
5454
ESP_MODEM_DCE_BG96,
5555
ESP_MODEM_DCE_SIM800,
56+
ESP_MODEM_DCE_CUSTOM
5657
} esp_modem_dce_device_t;
5758

5859
/**

components/esp_modem/include/generate/esp_modem_command_declare.inc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ ESP_MODEM_DECLARE_DCE_COMMAND(sync, command_result, 0) \
2525
\
2626
/**
2727
* @brief Reads the operator name
28-
* @param[out] operator name
29-
* @param[out] access technology
28+
* @param[out] name operator name
29+
* @param[out] act access technology
3030
* @return OK, FAIL or TIMEOUT
3131
*/ \
3232
ESP_MODEM_DECLARE_DCE_COMMAND(get_operator_name, command_result, 2, STRING_OUT(p1, name), INT_OUT(p2, act)) \
@@ -46,7 +46,7 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_pin, command_result, 1, STRING_IN(p1, pin)) \
4646
\
4747
/**
4848
* @brief Execute the supplied AT command
49-
* @param[in] at AT command
49+
* @param[in] cmd AT command
5050
* @param[out] out Command output string
5151
* @param[in] timeout AT command timeout in milliseconds
5252
* @return OK, FAIL or TIMEOUT
@@ -252,6 +252,8 @@ ESP_MODEM_DECLARE_DCE_COMMAND(set_preferred_mode, command_result, 1, INT_IN(p1,
252252
/**
253253
* @brief Set network bands for CAT-M or NB-IoT
254254
* @param[in] mode CAT-M or NB-IoT
255+
* @param[in] bands bitmap in hex representing bands
256+
* @param[in] size size of teh bands bitmap
255257
* @return OK, FAIL or TIMEOUT
256258
*/ \
257259
ESP_MODEM_DECLARE_DCE_COMMAND(set_network_bands, command_result, 3, STRING_IN(p1, mode), INTEGER_LIST_IN(p2, bands), INT_IN(p3, size)) \

0 commit comments

Comments
 (0)