Skip to content

Commit 269351f

Browse files
authored
Merge pull request #700 from david-cermak/feat/modem_pause_network
[modem]: Add support for pausing netif
2 parents 32387f7 + 5e92990 commit 269351f

File tree

15 files changed

+234
-22
lines changed

15 files changed

+234
-22
lines changed

components/esp_modem/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,11 @@ menu "esp-modem"
8585
mode more robust for some devices (e.g. Quectel), but might cause
8686
trouble for other devices (e.g. SIMCOM).
8787

88+
config ESP_MODEM_ADD_DEBUG_LOGS
89+
bool "Add UART Tx/Rx logs"
90+
default n
91+
help
92+
If enabled, the library dumps all transmitted and received data.
93+
This option is only used for debugging.
94+
8895
endmenu

components/esp_modem/examples/modem_console/main/modem_console_main.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,17 @@ extern "C" void app_main(void)
385385
return 0;
386386
});
387387
#endif
388+
const ConsoleCommand PauseNetwork("pause_net", "toggle network pause", no_args, [&](ConsoleCommand * c) {
389+
static int cnt = 0;
390+
if (++cnt % 2) {
391+
ESP_LOGI(TAG, "Pausing netif");
392+
dce->pause_netif(true);
393+
} else {
394+
ESP_LOGI(TAG, "Unpausing netif");
395+
dce->pause_netif(false);
396+
}
397+
return 0;
398+
});
388399

389400
const struct SetApn {
390401
SetApn(): apn(STR1, nullptr, nullptr, "<apn>", "APN (Access Point Name)") {}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,23 @@ menu "Example Configuration"
201201
help
202202
MQTT data message, which we publish and expect to receive.
203203

204+
config EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
205+
bool "Demonstrate netif pause"
206+
default n
207+
help
208+
Set this to true to demonstrate network pausing.
209+
If enabled, the example waits for an MQTT data, then temporarily
210+
drops network to check signal quality, resumes networking and
211+
publishes another MQTT message.
212+
Connection to the MQTT broker should be kept.
213+
214+
config EXAMPLE_DETECT_MODE_BEFORE_CONNECT
215+
bool "Detect mode before connect"
216+
default n
217+
help
218+
Set this to true to demonstrate mode auto-detection.
219+
If enabled, the example tries to recognize the actual mode.
220+
If mode is detected correctly and it is not a command mode,
221+
then the example switches to command mode.
222+
204223
endmenu

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

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Unlicense OR CC0-1.0
55
*/
@@ -34,6 +34,7 @@
3434
static const char *TAG = "pppos_example";
3535
static EventGroupHandle_t event_group = NULL;
3636
static const int CONNECT_BIT = BIT0;
37+
static const int DISCONNECT_BIT = BIT1;
3738
static const int GOT_DATA_BIT = BIT2;
3839
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
3940

@@ -55,6 +56,7 @@ static void usb_terminal_error_handler(esp_modem_terminal_error_t err)
5556
}
5657
#define CHECK_USB_DISCONNECTION(event_group) \
5758
if ((xEventGroupGetBits(event_group) & USB_DISCONNECTED_BIT) == USB_DISCONNECTED_BIT) { \
59+
ESP_LOGE(TAG, "USB_DISCONNECTED_BIT destroying modem dce"); \
5860
esp_modem_destroy(dce); \
5961
continue; \
6062
}
@@ -140,6 +142,7 @@ static void on_ip_event(void *arg, esp_event_base_t event_base,
140142
ESP_LOGI(TAG, "GOT ip event!!!");
141143
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
142144
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
145+
xEventGroupSetBits(event_group, DISCONNECT_BIT);
143146
} else if (event_id == IP_EVENT_GOT_IP6) {
144147
ESP_LOGI(TAG, "GOT IPv6 event!");
145148

@@ -158,6 +161,7 @@ void app_main(void)
158161
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL));
159162

160163
/* Configure the PPP netif */
164+
esp_err_t err;
161165
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
162166
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
163167
esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config);
@@ -205,7 +209,7 @@ void app_main(void)
205209
#endif
206210
assert(dce);
207211
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
208-
esp_err_t err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
212+
err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
209213
if (err != ESP_OK) {
210214
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
211215
return;
@@ -246,7 +250,27 @@ void app_main(void)
246250
#error Invalid serial connection to modem.
247251
#endif
248252

249-
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT);
253+
#if CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
254+
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
255+
256+
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_DETECT);
257+
if (err != ESP_OK) {
258+
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_DETECT) failed with %d", err);
259+
return;
260+
}
261+
esp_modem_dce_mode_t mode = esp_modem_get_mode(dce);
262+
ESP_LOGI(TAG, "Mode detection completed: current mode is: %d", mode);
263+
if (mode == ESP_MODEM_MODE_DATA) { // set back to command mode
264+
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
265+
if (err != ESP_OK) {
266+
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
267+
return;
268+
}
269+
ESP_LOGI(TAG, "Command mode restored");
270+
}
271+
#endif // CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
272+
273+
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
250274

251275
/* Run the modem demo app */
252276
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
@@ -262,7 +286,7 @@ void app_main(void)
262286
#endif
263287

264288
int rssi, ber;
265-
esp_err_t err = esp_modem_get_signal_quality(dce, &rssi, &ber);
289+
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
266290
if (err != ESP_OK) {
267291
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err));
268292
return;
@@ -301,22 +325,41 @@ void app_main(void)
301325
}
302326
/* Wait for IP address */
303327
ESP_LOGI(TAG, "Waiting for IP address");
304-
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
328+
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT, pdFALSE, pdFALSE,
329+
pdMS_TO_TICKS(60000));
305330
CHECK_USB_DISCONNECTION(event_group);
331+
if ((xEventGroupGetBits(event_group) & CONNECT_BIT) != CONNECT_BIT) {
332+
ESP_LOGW(TAG, "Modem not connected, switching back to the command mode");
333+
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
334+
if (err != ESP_OK) {
335+
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
336+
return;
337+
}
338+
ESP_LOGI(TAG, "Command mode restored");
339+
return;
340+
}
306341

307342
/* Config MQTT */
308-
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
309343
esp_mqtt_client_config_t mqtt_config = {
310344
.broker.address.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
311345
};
312-
#else
313-
esp_mqtt_client_config_t mqtt_config = {
314-
.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
315-
};
316-
#endif
317346
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
318347
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
319348
esp_mqtt_client_start(mqtt_client);
349+
350+
#if CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
351+
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
352+
esp_modem_pause_net(dce, true);
353+
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
354+
if (err != ESP_OK) {
355+
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d", err);
356+
return;
357+
}
358+
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);
359+
esp_modem_pause_net(dce, false);
360+
esp_mqtt_client_publish(mqtt_client, CONFIG_EXAMPLE_MQTT_TEST_TOPIC, CONFIG_EXAMPLE_MQTT_TEST_DATA, 0, 0, 0);
361+
#endif // CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
362+
320363
ESP_LOGI(TAG, "Waiting for MQTT data");
321364
xEventGroupWaitBits(event_group, GOT_DATA_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
322365
CHECK_USB_DISCONNECTION(event_group);

components/esp_modem/examples/pppos_client/pytest_pppos_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_pppos_connect(dut):
1212
4. checks that the client cleanly disconnects
1313
"""
1414
# Check the sequence of connecting, publishing, disconnecting
15-
dut.expect('Modem Connect to PPP Server')
15+
dut.expect('Modem Connect to PPP Server', timeout=90)
1616
# Check for MQTT connection and the data event
1717
dut.expect('MQTT_EVENT_CONNECTED')
1818
dut.expect('MQTT_EVENT_DATA')

components/esp_modem/examples/pppos_client/sdkconfig.ci.sim800_c3

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ CONFIG_EXAMPLE_MODEM_DEVICE_SIM800=y
1111
CONFIG_EXAMPLE_MODEM_DEVICE_BG96=n
1212
CONFIG_EXAMPLE_MODEM_PPP_APN="lpwa.vodafone.com"
1313
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
14+
CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL=y
1415
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
1516
CONFIG_ESP32_PANIC_PRINT_HALT=y
17+
CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT=y

components/esp_modem/examples/simple_cmux_client/sdkconfig.ci.sim800_cmux

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ CONFIG_COMPILER_CXX_EXCEPTIONS=y
1616
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
1717
CONFIG_EXAMPLE_CLOSE_CMUX_AT_END=y
1818
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
19+
CONFIG_BROKER_URI="mqtt://mqtt.eclipseprojects.io"

components/esp_modem/include/cxx_include/esp_modem_dce.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ class DCE_T {
9191
return mode.set(dte.get(), device.get(), netif, m);
9292
}
9393

94+
modem_mode get_mode()
95+
{
96+
return mode.get();
97+
}
98+
9499
bool recover()
95100
{
96101
return dte->recover();
@@ -103,6 +108,29 @@ class DCE_T {
103108
}
104109
#endif
105110

111+
/**
112+
* @brief Pauses/Unpauses network temporarily
113+
* @param do_pause true to pause, false to unpause
114+
* @param force true to ignore command failures and continue
115+
* @return command_result of the underlying commands
116+
*/
117+
command_result pause_netif(bool do_pause, bool force = false, int delay = 1000)
118+
{
119+
command_result result;
120+
if (do_pause) {
121+
netif.pause();
122+
Task::Delay(delay); // Mandatory 1s pause before
123+
dte->set_command_callbacks();
124+
result = device->set_command_mode();
125+
} else {
126+
result = device->resume_data_mode();
127+
if (result == command_result::OK || force) {
128+
netif.resume();
129+
}
130+
}
131+
return result;
132+
}
133+
106134
protected:
107135
std::shared_ptr<DTE> dte;
108136
std::shared_ptr<SpecificModule> device;

components/esp_modem/include/cxx_include/esp_modem_dte.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ class DTE : public CommandableIf {
145145
*/
146146
bool recover();
147147

148+
/**
149+
* @brief Set internal command callbacks to the underlying terminal.
150+
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
151+
*/
152+
void set_command_callbacks();
153+
148154
protected:
149155
/**
150156
* @brief Allows for locking the DTE
@@ -204,12 +210,6 @@ class DTE : public CommandableIf {
204210
} inflatable;
205211
#endif // CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
206212

207-
/**
208-
* @brief Set internal command callbacks to the underlying terminal.
209-
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
210-
*/
211-
void set_command_callbacks();
212-
213213
/**
214214
* @brief This abstracts command callback processing and implements its locking, signaling of completion and timeouts.
215215
*/

components/esp_modem/include/cxx_include/esp_modem_netif.hpp

Lines changed: 11 additions & 1 deletion
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-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -54,6 +54,16 @@ class Netif {
5454
*/
5555
void stop();
5656

57+
/**
58+
* @brief Pause the network interface
59+
*/
60+
void pause();
61+
62+
/**
63+
* @brief Resume the network interface
64+
*/
65+
void resume();
66+
5767
void receive(uint8_t *data, size_t len);
5868

5969
private:

0 commit comments

Comments
 (0)