mirror of
				https://github.com/espressif/esp-protocols.git
				synced 2025-11-04 00:21:37 +01: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();
							 | 
						||
| 
								 | 
							
								}
							 |