Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added `lists:keysort/2`
- Added `lists:merge/2,3`
- [ESP32] Added support to light sleep (`esp:light_sleep/0`) and to GPIO and timer wakeup from
light sleep.

### Fixed

Expand Down
45 changes: 45 additions & 0 deletions libs/eavmlib/src/esp.erl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
sleep_enable_ulp_wakeup/0,
deep_sleep/0,
deep_sleep/1,
light_sleep/0,
gpio_wakeup_enable/2,
sleep_enable_gpio_wakeup/0,
sleep_enable_timer_wakeup/1,
mount/4,
umount/1,
nvs_fetch_binary/2,
Expand Down Expand Up @@ -272,6 +276,47 @@ sleep_enable_ulp_wakeup() ->
deep_sleep() ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @doc Put the esp32 into light sleep.
%% This function returns ok on success after the sleep.
%% Program is NOT restarted and wake up reason can be inspected to determine how
%% the esp32 was woken up.
%% @end
%%-----------------------------------------------------------------------------
-spec light_sleep() -> ok | error.
light_sleep() ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @doc Configure given GPIO as light sleep wakeup pin
%% @param GPIONum the GPIO number
%% @param logic level, either low or high that triggers the wakeup condition
%% @returns `ok | error'
%% @end
%%-----------------------------------------------------------------------------
-spec gpio_wakeup_enable(GPIONum :: non_neg_integer(), Level :: low | high) -> ok | error.
gpio_wakeup_enable(_GPIONum, _Level) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @doc Enable waking up from light sleep using a configured GPIO
%% @returns `ok | error'
%% @end
%%-----------------------------------------------------------------------------
-spec sleep_enable_gpio_wakeup() -> ok | error.
sleep_enable_gpio_wakeup() ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @doc Enable waking up from light sleep using a timer
%% @param time before wakeup in microseconds
%% @returns `ok | error'
%% @end
%%-----------------------------------------------------------------------------
-spec sleep_enable_timer_wakeup(SleepUS :: non_neg_integer()) -> ok | error.
sleep_enable_timer_wakeup(_SleepUS) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param SleepMS time to deep sleep in milliseconds
%% @doc Put the esp32 into deep sleep.
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/esp32/components/avm_sys/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ idf_component_register(
SRCS ${AVM_SYS_COMPONENT_SRCS}
INCLUDE_DIRS "include"
REQUIRES "spi_flash" "soc" "newlib" "pthread" "vfs" "mbedtls" ${ADDITIONAL_COMPONENTS}
PRIV_REQUIRES "libatomvm" "esp_timer" ${ADDITIONAL_PRIV_REQUIRES}
PRIV_REQUIRES "libatomvm" "driver" "esp_timer" ${ADDITIONAL_PRIV_REQUIRES}
)

target_compile_features(${COMPONENT_LIB} INTERFACE c_std_11)
Expand Down
92 changes: 92 additions & 0 deletions src/platforms/esp32/components/avm_sys/platform_nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@
#include <esp_sleep.h>
#include <esp_system.h>
#include <esp_task_wdt.h>

// driver/gpio.h is required for wakeup from light sleep
#include <driver/gpio.h>
#include <mbedtls/cipher.h>
#include <mbedtls/md5.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>
#include <soc/soc.h>

#include <stdlib.h>

// introduced starting with 4.4
Expand Down Expand Up @@ -340,6 +344,17 @@ static term nif_esp_deep_sleep(Context *ctx, int argc, term argv[])
return OK_ATOM;
}

static term nif_esp_light_sleep(Context *ctx, int argc, term argv[])
{
UNUSED(ctx);
UNUSED(argc);
UNUSED(argv);

esp_err_t ret = esp_light_sleep_start();

return (ret == ESP_OK) ? OK_ATOM : ERROR_ATOM;
}

#if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT0_WAKEUP
static const char *const sleep_wakeup_ext0_atom = "\x11" "sleep_wakeup_ext0";
#endif
Expand Down Expand Up @@ -513,6 +528,47 @@ static term nif_esp_deep_sleep_enable_gpio_wakeup(Context *ctx, int argc, term a
}
#endif

static term nif_esp_gpio_wakeup_enable(Context *ctx, int argc, term argv[])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this gpio:wakeup_enable/2 to match with the esp-idf function name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this means we are leaking more ESP32 specific stuff into GPIO module. I think they can be made somehow generic, but I'm not sure how.

{
UNUSED(ctx);
UNUSED(argc);

VALIDATE_VALUE(argv[0], term_is_integer);
if ((argv[1] != LOW_ATOM) && (argv[1] != HIGH_ATOM)) {
RAISE_ERROR(BADARG_ATOM);
}

avm_int_t gpio = term_to_int(argv[0]);
gpio_int_type_t int_type = (argv[1] == LOW_ATOM) ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL;

esp_err_t ret = gpio_wakeup_enable(gpio, int_type);

return (ret == ESP_OK) ? OK_ATOM : ERROR_ATOM;
}

static term nif_esp_sleep_enable_gpio_wakeup(Context *ctx, int argc, term argv[])
{
UNUSED(ctx);
UNUSED(argc);
UNUSED(argv);

esp_err_t ret = esp_sleep_enable_gpio_wakeup();

return (ret == ESP_OK) ? OK_ATOM : ERROR_ATOM;
}

static term nif_esp_sleep_enable_timer_wakeup(Context *ctx, int argc, term argv[])
{
UNUSED(ctx);
UNUSED(argc);

VALIDATE_VALUE(argv[0], term_is_any_integer);
avm_int64_t us = term_maybe_unbox_int64(argv[0]);

esp_err_t ret = esp_sleep_enable_timer_wakeup(us);

return (ret == ESP_OK) ? OK_ATOM : ERROR_ATOM;
}

#if SOC_ULP_SUPPORTED

Expand Down Expand Up @@ -842,6 +898,11 @@ static const struct Nif esp_deep_sleep_nif =
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_deep_sleep
};
static const struct Nif esp_light_sleep_nif =
{
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_light_sleep
};
static const struct Nif esp_sleep_get_wakeup_cause_nif =
{
.base.type = NIFFunctionType,
Expand Down Expand Up @@ -880,6 +941,21 @@ static const struct Nif esp_deep_sleep_enable_gpio_wakeup_nif =
.nif_ptr = nif_esp_deep_sleep_enable_gpio_wakeup
};
#endif
static const struct Nif esp_gpio_wakeup_enable_nif =
{
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_gpio_wakeup_enable
};
static const struct Nif esp_sleep_enable_gpio_wakeup_nif =
{
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_sleep_enable_gpio_wakeup
};
static const struct Nif esp_sleep_enable_timer_wakeup_nif =
{
.base.type = NIFFunctionType,
.nif_ptr = nif_esp_sleep_enable_timer_wakeup
};
#if SOC_ULP_SUPPORTED
static const struct Nif esp_sleep_ulp_wakeup_nif =
{
Expand Down Expand Up @@ -981,6 +1057,10 @@ const struct Nif *platform_nifs_get_nif(const char *nifname)
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_deep_sleep_nif;
}
if (strcmp("esp:light_sleep/0", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_light_sleep_nif;
}
if (strcmp("esp:sleep_get_wakeup_cause/0", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_sleep_get_wakeup_cause_nif;
Expand Down Expand Up @@ -1013,6 +1093,18 @@ const struct Nif *platform_nifs_get_nif(const char *nifname)
return &esp_deep_sleep_enable_gpio_wakeup_nif;
}
#endif
if (strcmp("esp:gpio_wakeup_enable/2", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_gpio_wakeup_enable_nif;
}
if (strcmp("esp:sleep_enable_gpio_wakeup/0", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_sleep_enable_gpio_wakeup_nif;
}
if (strcmp("esp:sleep_enable_timer_wakeup/1", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
return &esp_sleep_enable_timer_wakeup_nif;
}
#if SOC_ULP_SUPPORTED
if (strcmp("esp:sleep_ulp_wakeup/0", nifname) == 0) {
TRACE("Resolved platform nif %s ...\n", nifname);
Expand Down
Loading