The idea is to detect the type of clicks, so If I start a timer once a single click is detected, click count = 1, a timer starts (<.5 sec or so) and the system goes back to sleep. If a second click is detected then click count = 2 and thus the click type is a quick double-click. If the
original timer times out then a second click was not detected and the click type is a single click. Thus it's not necessary to calculate the time difference between wake stub calls, just start a timer that times out after a certain duration.
Below is the modified version of your code implemented on MOS, the click count while in deep sleep does work. The code snippet marked "
Calculate timer difference" doesn't seem to be.
Code: Select all
#include "mgos.h"
#include "mgos_gpio.h"
#include "mgos_adc.h"
#include "mgos_timers.h"
#include "mgos_mqtt.h"
#include "esp_sleep.h"
#include "mgos_hal.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdio.h"
#include "mgos_sys_config.h"
#include "mgos_app.h"
#include "common/platform.h"
#include "driver/rtc_io.h"
#include "esp_attr.h"
#include "rom/rtc.h"
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/uart_reg.h"
#include "soc/timer_group_reg.h"
#include "soc/timer_group_struct.h"
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#include <time.h>
#include <sys/time.h>
// Assign GPIO and analog inputs based on pin values stored in config settings
#define LIGHT get_cfg()->iD_app.led_pin
#define RGB_LED get_cfg()->iD_app.rgb_led_pin
#define BUTTON get_cfg()->iD_app.button_pin
#define BUTTON_SENSOR get_cfg()->iD_app.button_sensor
#define WAKEUP_PIN get_cfg()->iD_app.wakeup_pin
#define BATTERY get_cfg()->iD_app.battery_sensor
// Assign time to wait in config mode before going to sleep
#define CONFIG_TIMEOUT 0.25 // minutes
mgos_timer_id sleep_timer = false;
// Deep sleep wake variables
RTC_DATA_ATTR int click_count;
RTC_DATA_ATTR int click_count_threshold = 20;
#define PULSE_CNT_RTC_GPIO_NUM 13
#define PULSE_CNT_GPIO_NUM 33
#define PULSE_CNT_IS_LOW() \
((REG_GET_FIELD(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT) \
& BIT(PULSE_CNT_RTC_GPIO_NUM)) == 0)
////////////////////////////////////////////////////////////////////////////////
// Deep sleep implementation
////////////////////////////////////////////////////////////////////////////////
// Identify wake-up reason and respond accordingly
static esp_sleep_wakeup_cause_t identify_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
LOG(LL_INFO, ("Wake up cause: Ext0 RTC_IO"));
break;
case ESP_SLEEP_WAKEUP_EXT1:
LOG(LL_INFO, ("Wake up cause: Ext1 RTC_IO"));
break;
case ESP_SLEEP_WAKEUP_TIMER:
LOG(LL_INFO, ("Wake up cause: Ext RTC_CNTL"));
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
LOG(LL_INFO, ("Wake up cause: Touchpad"));
break;
case ESP_SLEEP_WAKEUP_ULP:
LOG(LL_INFO, ("Wake up cause: ULP"));
break;
case ESP_SLEEP_WAKEUP_UNDEFINED:
LOG(LL_INFO, ("Wake up cause: Undefined"));
break;
default:
LOG(LL_INFO, ("Wake up cause: Default"));
break;
}
LOG(LL_INFO, ("Click count: %d", click_count));
return wakeup_reason;
}
RTC_DATA_ATTR uint64_t RTC_time;
// Code that executes immediately upon wake-up before other code is run
static void RTC_IRAM_ATTR wake_stub() {
static RTC_RODATA_ATTR const char fmt_str[] = "Click count too small: %d. Going back to sleep.\n";
click_count++;
esp_default_wake_deep_sleep();
// Calculate timer different EXPERIMENTAL****************************
SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE);
while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) {
ets_delay_us(1); // might take 1 RTC slowclk period, don't flood RTC bus
}
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR);
uint64_t t = READ_PERI_REG(RTC_CNTL_TIME0_REG);
t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32;
RTC_time = t;
static RTC_RODATA_ATTR const char t_str[] = "Current time: %d\n";
ets_printf(t_str, RTC_time);
// Calculate timer different EXPERIMENTAL****************************
// Experimental code for putting device back to sleep
if (click_count >= click_count_threshold) {
esp_default_wake_deep_sleep();
static RTC_RODATA_ATTR const char fmt_str[] = "Click count: %d. Waking up!\n";
ets_printf(fmt_str, click_count);
return;
}
//////////////////////////////////////////////////////////////////////////////
// If click_count_threshold is set to 1, only the code above executes and the
// device wakes normally. But if the click_count_threshold is > 1, the device
// goes back to sleep immediately after the first click (as it should), but
// can't wake again. There must be a problem in the code below (I suspect in
// the first 'do' loop - see my comments below).
//////////////////////////////////////////////////////////////////////////////
ets_printf(fmt_str, click_count);
do {
// CODE GETS STUCK HERE - UNCOMMENT THE LOG LINE TO SEE THE ISSUE
while (PULSE_CNT_IS_LOW()) {
REG_WRITE(TIMG_WDTFEED_REG(0), 1);
}
// debounce, 10ms
ets_delay_us(10000);
} while (PULSE_CNT_IS_LOW());
// Wait for UART to end transmitting.
while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {
;
}
// Set the pointer of the wake stub function.
REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)&wake_stub);
// Go to sleep.
// This line will only print a G, since there is not enough time to transmit the entire string before the device sleeps.
static RTC_RODATA_ATTR const char slp_str[] = "Going back to sleep %d\n";
ets_printf(slp_str, click_count);
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
// A few CPU cycles may be necessary for the sleep to start...
while (true) {
;
}
}
// Function for putting system to sleep
static void go_to_sleep() {
LOG(LL_INFO, ("Going to sleep...zzz"));
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO);
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN, 0);
esp_set_deep_sleep_wake_stub(&wake_stub);
esp_deep_sleep_start();
}
////////////////////////////////////////////////////////////////////////////////
// Main app function
////////////////////////////////////////////////////////////////////////////////
enum mgos_app_init_result mgos_app_init(void) {
// Set GPIO pin modes and initialize
mgos_gpio_set_mode(LIGHT, MGOS_GPIO_MODE_OUTPUT);
mgos_gpio_set_mode(RGB_LED, MGOS_GPIO_MODE_OUTPUT);
mgos_gpio_set_mode(BUTTON, MGOS_GPIO_MODE_INPUT);
mgos_gpio_set_mode(BUTTON_SENSOR, MGOS_GPIO_MODE_INPUT);
// Create a timer for going to sleep when timer triggers
sleep_timer = mgos_set_timer(CONFIG_TIMEOUT*30*1000, 0, go_to_sleep, NULL);
// Initialize light to 'on' state
LOG(LL_INFO, ("AWAKE!!! Turning light on"));
mgos_gpio_write(LIGHT, 1);
identify_wakeup_reason();
return MGOS_APP_INIT_SUCCESS;
}