mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-18 04:52:18 +02:00
203 lines
7.4 KiB
C
203 lines
7.4 KiB
C
![]() |
/*
|
||
|
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||
|
*
|
||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Power Saving Mode(PSM) in Sim70XX modems along with
|
||
|
* Deep sleep and Light Sleep modes in esp32.
|
||
|
*/
|
||
|
#include "freertos/FreeRTOS.h"
|
||
|
#include "freertos/task.h"
|
||
|
#include "esp_system.h"
|
||
|
#include "esp_log.h"
|
||
|
#include "driver/uart.h"
|
||
|
#include "string.h"
|
||
|
#include "driver/gpio.h"
|
||
|
#include "esp_sleep.h"
|
||
|
#include "driver/rtc_io.h"
|
||
|
#include "esp_modem_api.h"
|
||
|
#include "esp_event.h"
|
||
|
#include "sdkconfig.h"
|
||
|
|
||
|
|
||
|
#define BUF_SIZE 1024
|
||
|
|
||
|
#define TXD_PIN ((gpio_num_t)CONFIG_EXAMPLE_MODEM_UART_TX_PIN)
|
||
|
#define RXD_PIN ((gpio_num_t)CONFIG_EXAMPLE_MODEM_UART_RX_PIN)
|
||
|
#define GPIO_INPUT_STATUS ((gpio_num_t)CONFIG_EXAMPLE_MODEM_STATUS_PIN)
|
||
|
#define GPIO_OUTPUT_PWRKEY ((gpio_num_t)CONFIG_EXAMPLE_MODEM_PWRKEY_PIN)
|
||
|
#define GPIO_OUTPUT_PIN_SEL (1ULL<<GPIO_OUTPUT_PWRKEY)
|
||
|
|
||
|
#define CHECK_ERR(cmd, success_action) do { \
|
||
|
esp_err_t ret = cmd; \
|
||
|
if (ret == ESP_OK) { \
|
||
|
success_action; \
|
||
|
} else { \
|
||
|
ESP_LOGE(TAG, "Failed with %s", ret == ESP_ERR_TIMEOUT ? "TIMEOUT":"ERROR"); \
|
||
|
} } while (0)
|
||
|
|
||
|
|
||
|
const char *TAG = "modem_psm";
|
||
|
RTC_DATA_ATTR static int boot_count = 0;
|
||
|
|
||
|
|
||
|
void dce_init(esp_modem_dce_t **dce, esp_netif_t **esp_netif)
|
||
|
{
|
||
|
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
|
||
|
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
|
||
|
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
|
||
|
*esp_netif = esp_netif_new(&netif_ppp_config);
|
||
|
assert(*esp_netif);
|
||
|
|
||
|
/* setup UART specific configuration based on kconfig options */
|
||
|
dte_config.uart_config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN;
|
||
|
dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN;
|
||
|
dte_config.uart_config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE;
|
||
|
dte_config.uart_config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE;
|
||
|
dte_config.uart_config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE;
|
||
|
dte_config.task_stack_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE;
|
||
|
dte_config.task_priority = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY;
|
||
|
dte_config.dte_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE / 2;
|
||
|
|
||
|
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
|
||
|
*dce = esp_modem_new(&dte_config, &dce_config, *esp_netif);
|
||
|
assert(*dce);
|
||
|
}
|
||
|
|
||
|
void config_pwrkey_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 power_on_modem(esp_modem_dce_t *dce)
|
||
|
{
|
||
|
rtc_gpio_hold_dis(GPIO_OUTPUT_PWRKEY);
|
||
|
|
||
|
/* Power on the modem */
|
||
|
ESP_LOGI(TAG, "Power on the modem");
|
||
|
gpio_set_level(GPIO_OUTPUT_PWRKEY, 1);
|
||
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||
|
gpio_set_level(GPIO_OUTPUT_PWRKEY, 0);
|
||
|
|
||
|
rtc_gpio_hold_en(GPIO_OUTPUT_PWRKEY);
|
||
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||
|
|
||
|
CHECK_ERR(esp_modem_sync(dce), ESP_LOGI(TAG, "OK"));
|
||
|
}
|
||
|
|
||
|
void power_down_modem(esp_modem_dce_t *dce)
|
||
|
{
|
||
|
char data[BUF_SIZE];
|
||
|
|
||
|
ESP_LOGI(TAG, "Power down the modem");
|
||
|
|
||
|
/* Power down the modem by AT command */
|
||
|
CHECK_ERR(esp_modem_at(dce, "AT+CPOWD=1", data, 500), ESP_LOGI(TAG, "OK. %s", data));
|
||
|
}
|
||
|
|
||
|
void run_at(esp_modem_dce_t *dce, uint8_t count)
|
||
|
{
|
||
|
for (int i = 0; i < count; i++) {
|
||
|
CHECK_ERR(esp_modem_sync(dce), ESP_LOGI(TAG, "OK"));
|
||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void run_at_ping(esp_modem_dce_t *dce)
|
||
|
{
|
||
|
char data[BUF_SIZE];
|
||
|
int rssi, ber;
|
||
|
CHECK_ERR(esp_modem_get_signal_quality(dce, &rssi, &ber), ESP_LOGI(TAG, "OK. rssi=%d, ber=%d", rssi, ber));
|
||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
|
||
|
CHECK_ERR(esp_modem_at(dce, "AT+CPSMS?", data, 500), ESP_LOGI(TAG, "OK. %s", data));
|
||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
|
||
|
CHECK_ERR(esp_modem_at(dce, "AT+CPSI?", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Inquiring UE system information
|
||
|
CHECK_ERR(esp_modem_at(dce, "AT+CNACT=0,1", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Activate the APP network
|
||
|
CHECK_ERR(esp_modem_at(dce, "AT+SNPDPID=0", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Select PDP index for PING
|
||
|
CHECK_ERR(esp_modem_at(dce, "AT+SNPING4=\"8.8.8.8\",3,16,1000", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Send IPv4 PING
|
||
|
CHECK_ERR(esp_modem_at(dce, "AT+CNACT=0,0", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Deactivate the APP network
|
||
|
}
|
||
|
|
||
|
|
||
|
void app_main(void)
|
||
|
{
|
||
|
char *cmd;
|
||
|
char data[BUF_SIZE];
|
||
|
esp_modem_dce_t *dce = NULL;
|
||
|
esp_netif_t *esp_netif = NULL;
|
||
|
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
|
||
|
ESP_LOGI(TAG, "Deep sleep Wake Up Cause: %d\n", wakeup_cause);
|
||
|
|
||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||
|
|
||
|
dce_init(&dce, &esp_netif);
|
||
|
|
||
|
switch (wakeup_cause) {
|
||
|
case ESP_SLEEP_WAKEUP_UNDEFINED:
|
||
|
/* Power on the modem */
|
||
|
config_pwrkey_gpio();
|
||
|
power_on_modem(dce);
|
||
|
|
||
|
run_at(dce, 3);
|
||
|
|
||
|
/* Configure Power Saving Mode in the modem */
|
||
|
asprintf(&cmd, "AT+CPSMS=1,,,\"%s\",\"%s\"\r\n", CONFIG_EXAMPLE_MODEM_T3412_PERIODIC_TAU,
|
||
|
CONFIG_EXAMPLE_MODEM_T3324_ACTIVE_TIME);
|
||
|
CHECK_ERR(esp_modem_at(dce, cmd, data, 500), ESP_LOGI(TAG, "OK. %s", data));
|
||
|
free(cmd);
|
||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
|
||
|
/* Perform Communication tasks */
|
||
|
run_at_ping(dce);
|
||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
break;
|
||
|
|
||
|
case ESP_SLEEP_WAKEUP_EXT0:
|
||
|
run_at(dce, 3);
|
||
|
|
||
|
/* Perform Communication tasks */
|
||
|
run_at_ping(dce);
|
||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ESP_LOGI(TAG, "Not a deep sleep reset: %d\n", wakeup_cause);
|
||
|
}
|
||
|
|
||
|
ESP_LOGI(TAG, "Light sleep before going to Deep sleep\n\n");
|
||
|
|
||
|
/* Enter light sleep mode as long as the modem is awake */
|
||
|
esp_sleep_enable_timer_wakeup(CONFIG_EXAMPLE_MODEM_LIGHT_SLEEP_DURATION * 1000000);
|
||
|
esp_light_sleep_start();
|
||
|
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); // Disabling timer before going to deep sleep.
|
||
|
wakeup_cause = esp_sleep_get_wakeup_cause();
|
||
|
ESP_LOGI(TAG, "Light sleep wakeup cause: %d\n", wakeup_cause);
|
||
|
|
||
|
/* DCE and netif clean-up */
|
||
|
/* In Deep-sleep mode, the CPUs, most of the RAM, and all digital peripherals are powered off.
|
||
|
* So dce and netif would be lost anyway if they are not explicitly destroyed.
|
||
|
* But since dce is also linked with UART communication with the modem it's better to exit gracefully before going to deep sleep.
|
||
|
*/
|
||
|
esp_modem_destroy(dce);
|
||
|
esp_netif_destroy(esp_netif);
|
||
|
|
||
|
/* Enable wakeup if status pin is high */
|
||
|
esp_sleep_enable_ext0_wakeup(GPIO_INPUT_STATUS, 1);
|
||
|
|
||
|
ESP_LOGI(TAG, "Entering deep sleep: %d\n", boot_count++);
|
||
|
esp_deep_sleep_start();
|
||
|
}
|