esp_modem: Added modem_console commands for deep-sleep and modem PSM.

This commit is contained in:
Abhik Roy
2022-10-06 22:34:21 +05:30
parent a9b5e66d0f
commit 85a2e25093
3 changed files with 159 additions and 12 deletions

View File

@ -163,4 +163,10 @@ menu "Example Configuration"
Buffer size of UART RX buffer.
endmenu
config EXAMPLE_MODEM_PWRKEY_PIN
int "PWRKEY Pin Number"
default 18
range 0 31
help
Pin number connected to modem's power key pin.
endmenu

View File

@ -15,6 +15,8 @@
#include "esp_console.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_sleep.h"
#include "driver/gpio.h"
#include "cxx_include/esp_modem_dte.hpp"
#include "esp_modem_config.h"
#include "cxx_include/esp_modem_api.hpp"
@ -41,7 +43,7 @@
return 0; \
} else { \
ESP_LOGE(TAG, "Failed with %s", err == command_result::TIMEOUT ? "TIMEOUT":"ERROR"); \
return 1; \
return 1; \
} } while (0)
/**
@ -49,6 +51,9 @@
*/
#define DEFAULT_APN "my_apn"
#define GPIO_OUTPUT_PWRKEY (gpio_num_t)CONFIG_EXAMPLE_MODEM_PWRKEY_PIN
#define GPIO_OUTPUT_PIN_SEL (1ULL<<GPIO_OUTPUT_PWRKEY)
extern "C" void modem_console_register_http(void);
extern "C" void modem_console_register_ping(void);
@ -59,8 +64,37 @@ using namespace esp_modem;
static SignalGroup exit_signal;
void config_gpio(void)
{
gpio_config_t io_conf = {}; //zero-initialize the config structure.
io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; //bit mask of the pins that you want to set,e.g.GPIO18/19
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; //disable pull-down mode
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; //disable pull-up mode
gpio_config(&io_conf); //configure GPIO with the given settings
}
void wakeup_modem(void)
{
/* Power on the modem */
ESP_LOGI(TAG, "Power on the modem");
gpio_set_level(GPIO_OUTPUT_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(1000));
gpio_set_level(GPIO_OUTPUT_PWRKEY, 0);
vTaskDelay(pdMS_TO_TICKS(2000));
}
extern "C" void app_main(void)
{
static RTC_RODATA_ATTR char apn_rtc[20] = DEFAULT_APN;
static RTC_DATA_ATTR modem_mode mode_rtc = esp_modem::modem_mode::COMMAND_MODE;
config_gpio();
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
@ -115,7 +149,7 @@ extern "C" void app_main(void)
while (1) {
exit_signal.clear(1);
struct esp_modem_usb_term_config usb_config = ESP_MODEM_DEFAULT_USB_CONFIG(0x2C7C, 0x0296, 2); // VID, PID and interface num of BG96 modem
const esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
const esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_USB_CONFIG(usb_config);
ESP_LOGI(TAG, "Waiting for USB device connection...");
auto dte = create_usb_dte(&dte_config);
dte->set_error_cb([&](terminal_error err) {
@ -129,10 +163,10 @@ extern "C" void app_main(void)
#else
#error Invalid serial connection to modem.
#endif
assert(dce != nullptr);
if(dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
if (command_result::OK != dce->set_flow_control(2, 2)) {
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
return;
@ -145,6 +179,26 @@ extern "C" void app_main(void)
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
switch (esp_sleep_get_wakeup_cause()) {
case ESP_SLEEP_WAKEUP_TIMER:
if (esp_modem::modem_mode::CMUX_MODE == mode_rtc) {
ESP_LOGI(TAG, "Deep sleep reset\n");
/* Set APN */
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn_rtc));
dce->get_module()->configure_pdp_context(std::move(new_pdp));
/* Set CMUX mode */
if (!dce->set_mode(mode_rtc)) {
ESP_LOGE(TAG, "Failed to set the desired mode");
}
}
break;
case ESP_SLEEP_WAKEUP_UNDEFINED:
default:
ESP_LOGD(TAG, "Not a deep sleep reset\n");
}
modem_console_register_http();
modem_console_register_ping();
const struct SetModeArgs {
@ -160,7 +214,10 @@ extern "C" void app_main(void)
} else if (mode == "PPP") {
dev_mode = esp_modem::modem_mode::DATA_MODE;
} else if (mode == "CMUX") {
/* Even if switching to CMUX fails, we make the DTE multiplex terminal.
(This is potentially a bug and might be fixed eventually) */
dev_mode = esp_modem::modem_mode::CMUX_MODE;
mode_rtc = dev_mode;
} else {
ESP_LOGE(TAG, "Unsupported mode: %s", mode.c_str());
return 1;
@ -170,6 +227,8 @@ extern "C" void app_main(void)
ESP_LOGE(TAG, "Failed to set the desired mode");
return 1;
}
mode_rtc = dev_mode;
ESP_LOGI(TAG, "OK");
}
return 0;
@ -277,6 +336,7 @@ extern "C" void app_main(void)
if (c->get_count_of(&SetApn::apn)) {
auto apn = c->get_string_of(&SetApn::apn);
ESP_LOGI(TAG, "Setting the APN=%s...", apn.c_str());
strcpy(apn_rtc, apn.c_str());
auto new_pdp = std::unique_ptr<PdpContext>(new PdpContext(apn));
dce->get_module()->configure_pdp_context(std::move(new_pdp));
ESP_LOGI(TAG, "OK");
@ -289,6 +349,83 @@ extern "C" void app_main(void)
exit_signal.set(1);
return 0;
});
/* Put the esp32 into deep sleep */
const struct DeepSleepArgs {
DeepSleepArgs(): timeout(INT1, nullptr, nullptr, "<tout>", "TIMEOUT") {}
CommandArgs timeout;
} deep_sleep_args;
const ConsoleCommand SetDeepSleep("set_deep_sleep", "Put esp32 to deep sleep", &deep_sleep_args, sizeof(deep_sleep_args), [&](ConsoleCommand * c) {
int tout = c->get_int_of(&DeepSleepArgs::timeout);
ESP_LOGI(TAG, "Entering deep sleep for %d sec", tout);
ESP_LOGI(TAG, "Wakeup Cause: %d ", esp_sleep_get_wakeup_cause());
esp_deep_sleep(tout * 1000000);
return 0;
});
/* Wake up modem */
const ConsoleCommand WakeupModem("wakeup_modem", "Wakes up the modem from PSM", no_args, [&](ConsoleCommand * c) {
wakeup_modem();
ESP_LOGI(TAG, "OK");
return 0;
});
/* Enable PSM modem */
const ConsoleCommand EnablePSM("enable_psm", "Enables PSM on the modem", no_args, [&](ConsoleCommand * c) {
std::string out;
CHECK_ERR(dce->at("AT+CPSMS=1", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
return 0;
});
/* Disable PSM modem */
const ConsoleCommand DisablePSM("disable_psm", "Disables PSM on the modem", no_args, [&](ConsoleCommand * c) {
std::string out;
CHECK_ERR(dce->at("AT+CPSMS=0", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
return 0;
});
/* Get modem PSM cfg */
const ConsoleCommand GetModemCfg("get_psm_cfg", "Get PSM config", no_args, [&](ConsoleCommand * c) {
std::string out;
CHECK_ERR(dce->at("AT+CPSMS?", out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
return 0;
});
/* Set modem PSM config */
const struct SetPsmCfgArgs {
SetPsmCfgArgs():
periodic_tau(STR1, nullptr, nullptr, "<Requested_Periodic-TAU>", "T3412 Timer in 8-bit format"),
active_time(STR0, nullptr, nullptr, "<Requested_Active-Time>", "T3324 Timer in 8-bit format") {}
CommandArgs periodic_tau;
CommandArgs active_time;
} set_psm_cfg_args;
const ConsoleCommand SetPsmCfg("set_psm_cfg", "Set PSM config", &set_psm_cfg_args, sizeof(set_psm_cfg_args), [&](ConsoleCommand * c) {
std::string out;
auto periodic_tau = c->get_string_of(&SetPsmCfgArgs::periodic_tau);
auto active_time = c->get_string_of(&SetPsmCfgArgs::active_time);
/* Validate input */
if ((strlen(periodic_tau.c_str()) != strlen("00000000")) ||
(strlen(active_time.c_str()) != strlen("00000000"))) {
ESP_LOGE(TAG, "Failed with ERROR: Invalid argument length");
return 1;
}
/* Get PSM config */
dce->at("AT+CPSMS?", out, 500);
/* Update PSM config */
if (out.size() > 8) {
std::string set_cmd = "AT+CPSMS=" + std::to_string(out.c_str()[8] - '0') + ",,,\"" + periodic_tau.c_str() + "\",\"" + active_time.c_str() + "\"";
CHECK_ERR(dce->at(set_cmd, out, 500), ESP_LOGI(TAG, "OK. %s", out.c_str()));
} else {
ESP_LOGE(TAG, "Failed with ERROR: Invalid AT+CPSMS? return length");
}
return 0;
});
// start console REPL
ESP_ERROR_CHECK(esp_console_start_repl(s_repl));
// wait for exit
@ -296,7 +433,7 @@ extern "C" void app_main(void)
s_repl->del(s_repl);
ESP_LOGI(TAG, "Exiting...%d", esp_get_free_heap_size());
#if defined(CONFIG_EXAMPLE_SERIAL_CONFIG_USB)
// USB example runs in a loop to demonstrate hot-plugging and sudden disconnection features.
} // while (1)
// USB example runs in a loop to demonstrate hot-plugging and sudden disconnection features.
} // while (1)
#endif
}

View File

@ -1,8 +1,12 @@
# Override some defaults to enable PPP
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32c3"
CONFIG_EXAMPLE_MODEM_DEVICE_SIM7600=y
CONFIG_EXAMPLE_MODEM_UART_TX_PIN=4
CONFIG_EXAMPLE_MODEM_UART_RX_PIN=5
CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE=4096
CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168
CONFIG_LWIP_PPP_SUPPORT=y
# CONFIG_LWIP_PPP_ENABLE_IPV6 is not set
CONFIG_LWIP_PPP_PAP_SUPPORT=y
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
# Do not enable IPV6 in dte<->dce link local
CONFIG_LWIP_PPP_ENABLE_IPV6=n
# Disable legacy API
CONFIG_MODEM_LEGACY_API=n