add (some) spurious IR detection capability

This commit is contained in:
philippe44
2023-09-18 18:34:03 -07:00
parent a76ce3f344
commit e0e749fb5b
3 changed files with 142 additions and 83 deletions

View File

@@ -22,6 +22,8 @@ static const char* TAG = "IR";
#define IR_TOOLS_FLAGS_PROTO_EXT (1 << 0) /*!< Enable Extended IR protocol */
#define IR_TOOLS_FLAGS_INVERSE (1 << 1) /*!< Inverse the IR signal, i.e. take high level as low, and vice versa */
static int8_t ir_gpio = -1;
/**
* @brief IR device type
*
@@ -478,6 +480,12 @@ bool infrared_receive(RingbufHandle_t rb, infrared_handler handler) {
return decoded;
}
/****************************************************************************************
*
*/
int8_t infrared_gpio(void) {
return ir_gpio;
};
/****************************************************************************************
*
@@ -491,6 +499,7 @@ void infrared_init(RingbufHandle_t *rb, int gpio, infrared_mode_t mode) {
ir_parser_config.flags |= IR_TOOLS_FLAGS_PROTO_EXT; // Using extended IR protocols (both NEC and RC5 have extended version)
ir_parser = (mode == IR_NEC) ? ir_parser_rmt_new_nec(&ir_parser_config) : ir_parser_rmt_new_rc5(&ir_parser_config);
ir_gpio = gpio;
// get RMT RX ringbuffer
rmt_get_ringbuf_handle(rmt_channel, rb);

View File

@@ -17,4 +17,5 @@ typedef void (*infrared_handler)(uint16_t addr, uint16_t cmd);
bool infrared_receive(RingbufHandle_t rb, infrared_handler handler);
void infrared_init(RingbufHandle_t *rb, int gpio, infrared_mode_t mode);
int8_t infrared_gpio(void);

View File

@@ -46,7 +46,7 @@ pwm_system_t pwm_system = {
static EXT_RAM_ATTR struct {
uint64_t wake_gpio, wake_level;
uint64_t rtc_gpio, rtc_level;
uint32_t delay;
uint32_t delay, spurious;
float battery_level;
int battery_count;
void (*idle_chain)(uint32_t now);
@@ -110,23 +110,50 @@ static void sleep_gpio_handler(void *id, button_event_e event, button_press_e mo
*
*/
static void sleep_timer(uint32_t now) {
static uint32_t last;
static EXT_RAM_ATTR uint32_t last, first;
// first chain the calls to psudo_idle function
// first chain the calls to pseudo_idle function
if (sleep_context.idle_chain) sleep_context.idle_chain(now);
// we need boot time for spurious timeout calculation
if (!first) first = now;
// only query callbacks every 30s if we have at least one sleeper
if (!*sleep_context.sleeper || now < last + 30*1000) return;
last = now;
// call all sleep hooks that might want to do something
for (uint32_t (**sleeper)(void) = sleep_context.sleeper; *sleeper; sleeper++) {
// time to evaluate if we had spurious wake-up
if (sleep_context.spurious && now > sleep_context.spurious + first) {
bool spurious = true;
// see if at least one sleeper has been awake since we started
for (uint32_t (**sleeper)(void) = sleep_context.sleeper; *sleeper && spurious; sleeper++) {
spurious &= (*sleeper)() >= now - first;
}
// no activity since we woke-up, this was a spurious one
if (spurious) {
ESP_LOGI(TAG, "spurious wake of %d sec, going back to sleep", (now - first) / 1000);
services_sleep_activate(SLEEP_ONTIMER);
}
// resume normal work but we might have no "regular" inactivity delay
sleep_context.spurious = 0;
if (!sleep_context.delay) *sleep_context.sleeper = NULL;
ESP_LOGI(TAG, "wake-up was not spurious after %d sec", (now - first) / 1000);
}
// we might be here because we are waiting for spurious
if (sleep_context.delay) {
// call all sleepers to know how long for how long they have been inactive
for (uint32_t (**sleeper)(void) = sleep_context.sleeper; sleep_context.delay && *sleeper; sleeper++) {
if ((*sleeper)() < sleep_context.delay) return;
}
// if we are here, we are ready to sleep;
services_sleep_activate(SLEEP_ONTIMER);
}
}
/****************************************************************************************
*
@@ -150,23 +177,6 @@ static void sleep_init(void) {
char *config = config_alloc_get(NVS_TYPE_STR, "sleep_config");
char *p;
// do we want delay sleep
PARSE_PARAM(config, "delay", '=', sleep_context.delay);
sleep_context.delay *= 60*1000;
if (sleep_context.delay) {
sleep_context.idle_chain = pseudo_idle_svc;
pseudo_idle_svc = sleep_timer;
ESP_LOGI(TAG, "Sleep inactivity of %d minute(s)", sleep_context.delay / (60*1000));
}
// do we want battery safety
PARSE_PARAM_FLOAT(config, "batt", '=', sleep_context.battery_level);
if (sleep_context.battery_level != 0.0) {
sleep_context.battery_chain = battery_handler_svc;
battery_handler_svc = sleep_battery;
ESP_LOGI(TAG, "Sleep on battery level of %.2f", sleep_context.battery_level);
}
// get the wake criteria
if ((p = strcasestr(config, "wake"))) {
char list[32] = "", item[8];
@@ -189,6 +199,15 @@ static void sleep_init(void) {
}
}
// do we want battery safety
PARSE_PARAM_FLOAT(config, "batt", '=', sleep_context.battery_level);
if (sleep_context.battery_level != 0.0) {
sleep_context.battery_chain = battery_handler_svc;
battery_handler_svc = sleep_battery;
ESP_LOGI(TAG, "Sleep on battery level of %.2f", sleep_context.battery_level);
}
// get the rtc-pull criteria
if ((p = strcasestr(config, "rtc"))) {
char list[32] = "", item[8];
@@ -211,7 +230,7 @@ static void sleep_init(void) {
}
}
// then get the gpio that activate sleep (we could check that we have a valid wake)
// get the GPIOs that activate sleep (we could check that we have a valid wake)
if ((p = strcasestr(config, "sleep"))) {
int gpio, level = 0;
char sleep[8] = "";
@@ -221,6 +240,36 @@ static void sleep_init(void) {
ESP_LOGI(TAG, "Sleep activation gpio %d (active %d)", gpio, level);
button_create(NULL, gpio, level ? BUTTON_HIGH : BUTTON_LOW, true, 0, sleep_gpio_handler, 0, -1);
}
// do we want delay sleep
PARSE_PARAM(config, "delay", '=', sleep_context.delay);
sleep_context.delay *= 60*1000;
// now check why we woke-up
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause == ESP_SLEEP_WAKEUP_EXT0 || cause == ESP_SLEEP_WAKEUP_EXT1) {
ESP_LOGI(TAG, "waking-up from deep sleep with cause %d", cause);
// find the type of wake-up
uint64_t wake_gpio;
if (cause == ESP_SLEEP_WAKEUP_EXT0) wake_gpio = sleep_context.wake_gpio;
else wake_gpio = esp_sleep_get_ext1_wakeup_status();
// we might be woken up by infrared in which case we want a short sleep
if (infrared_gpio() >= 0 && ((1LL << infrared_gpio()) & wake_gpio)) {
sleep_context.spurious = 1;
PARSE_PARAM(config, "spurious", '=', sleep_context.spurious);
sleep_context.spurious *= 60*1000;
ESP_LOGI(TAG, "spurious wake-up detection during %d sec", sleep_context.spurious / 1000);
}
}
// if we have inactivity timer (user-set or because of IR wake) then active counters
if (sleep_context.delay || sleep_context.spurious) {
sleep_context.idle_chain = pseudo_idle_svc;
pseudo_idle_svc = sleep_timer;
if (sleep_context.delay) ESP_LOGI(TAG, "inactivity timer of %d minute(s)", sleep_context.delay / (60*1000));
}
}
/****************************************************************************************