From f3a4ad8799df494ed2a669455e3b136212cb453c Mon Sep 17 00:00:00 2001 From: Winford Date: Sat, 21 Dec 2024 07:16:45 +0000 Subject: [PATCH] Fix ESP32 gpio driver error returns to match spec Changes error returns to match the spec and ofther platforms. Nifs now raise any errors, and port function errors return `{error, Reason}`. Updates gpio.erl to reflect the correct returns, and make it more clear that errors for nifs will be raised. Closes #894 Signed-off-by: Winford --- CHANGELOG.md | 1 + libs/eavmlib/src/gpio.erl | 58 +++---- .../components/avm_builtins/gpio_driver.c | 157 +++++++++++------- 3 files changed, 130 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 881c66b0a..9c986bb5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - ESP32: improved sntp sync speed from a cold boot. +- ESP32 GPIO driver now matches spec for error returns, nifs raise `Error`, port functions return `{error, Reason}` ## [0.6.6] - Unreleased diff --git a/libs/eavmlib/src/gpio.erl b/libs/eavmlib/src/gpio.erl index d0fac085a..b027387b5 100644 --- a/libs/eavmlib/src/gpio.erl +++ b/libs/eavmlib/src/gpio.erl @@ -82,7 +82,7 @@ %% Event type that will trigger a `gpio_interrupt'. STM32 only supports `rising', `falling', or `both'. %%----------------------------------------------------------------------------- -%% @returns Pid | error | {error, Reason} +%% @returns Pid | {error, Reason} %% @doc Start the GPIO driver port %% %% Returns the pid of the active GPIO port driver, otherwise the GPIO @@ -103,7 +103,7 @@ start() -> end. %%----------------------------------------------------------------------------- -%% @returns Pid | error | {error, Reason} +%% @returns Pid | {error, Reason} %% @doc Start the GPIO driver port %% %% The GPIO port driver will be stared and registered as `gpio'. If the @@ -121,7 +121,7 @@ open() -> %%----------------------------------------------------------------------------- %% @param GPIO pid that was returned from gpio:start/0 -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Stop the GPIO interrupt port %% %% This function disables any interrupts that are set, stops @@ -135,7 +135,7 @@ close(GPIO) -> port:call(GPIO, {close}). %%----------------------------------------------------------------------------- -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Stop the GPIO interrupt port %% %% This function disables any interrupts that are set, stops @@ -151,7 +151,7 @@ stop() -> %%----------------------------------------------------------------------------- %% @param GPIO pid that was returned from gpio:start/0 %% @param Pin number of the pin to read -%% @returns high | low | error | {error, Reason} +%% @returns high | low | {error, Reason} %% @doc Read the digital state of a GPIO pin %% %% Read if an input pin state is `high' or `low'. @@ -169,7 +169,7 @@ read(GPIO, Pin) -> %% @param GPIO pid that was returned from `gpio:start/0' %% @param Pin number of the pin to configure %% @param Direction is `input', `output', or `output_od' -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Set the operational mode of a pin %% %% Pins can be used for input, output, or output with open drain. @@ -199,7 +199,7 @@ set_direction(GPIO, Pin, Direction) -> %% @param GPIO pid that was returned from `gpio:start/0' %% @param Pin number of the pin to write %% @param Level the desired output level to set -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Set GPIO digital output level %% %% Set a pin to `high' (1) or `low' (0). @@ -233,7 +233,7 @@ set_level(GPIO, Pin, Level) -> %% @param GPIO pid that was returned from `gpio:start/0' %% @param Pin number of the pin to set the interrupt on %% @param Trigger is the state that will trigger an interrupt -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Set a GPIO interrupt %% %% Available triggers are `none' (which is the same as disabling an @@ -257,7 +257,7 @@ set_int(GPIO, Pin, Trigger) -> %% @param Pin number of the pin to set the interrupt on %% @param Trigger is the state that will trigger an interrupt %% @param Pid is the process that will receive the interrupt message -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Set a GPIO interrupt %% %% Available triggers are `none' (which is the same as disabling an @@ -280,7 +280,7 @@ set_int(GPIO, Pin, Trigger, Pid) -> %%----------------------------------------------------------------------------- %% @param GPIO pid that was returned from `gpio:start/0' %% @param Pin number of the pin to remove the interrupt -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Remove a GPIO interrupt %% %% Removes an interrupt from the specified pin. @@ -288,13 +288,13 @@ set_int(GPIO, Pin, Trigger, Pid) -> %% The rp2040 (Pico) port does not support gpio interrupts at this time. %% @end %%----------------------------------------------------------------------------- --spec remove_int(GPIO :: gpio(), Pin :: pin()) -> ok | {error, Reason :: atom()} | error. +-spec remove_int(GPIO :: gpio(), Pin :: pin()) -> ok | {error, Reason :: atom()}. remove_int(GPIO, Pin) -> port:call(GPIO, {remove_int, Pin}). %%----------------------------------------------------------------------------- %% @param Pin number to initialize -%% @returns ok +%% @returns ok | raise(Error) %% @doc Initialize a pin to be used as GPIO. %% This is required on RP2040 and for some pins on ESP32. %% @end @@ -305,7 +305,7 @@ init(_Pin) -> %%----------------------------------------------------------------------------- %% @param Pin number to deinitialize -%% @returns ok +%% @returns ok | raise(Error) %% @doc Reset a pin back to the NULL function. %% Currently only implemented for RP2040 (Pico). %% @end @@ -317,7 +317,7 @@ deinit(_Pin) -> %%----------------------------------------------------------------------------- %% @param Pin number to set operational mode %% @param Direction is `input', `output', or `output_od' -%% @returns ok | error | {error, Reason} +%% @returns ok | raise(Error) %% @doc Set the operational mode of a pin %% %% Pins can be used for input, output, or output with open drain. @@ -336,14 +336,14 @@ deinit(_Pin) -> %% @end %%----------------------------------------------------------------------------- -spec set_pin_mode(Pin :: pin(), Direction :: direction()) -> - ok | {error, Reason :: atom()} | error. + ok. set_pin_mode(_Pin, _Mode) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- %% @param Pin number to set internal resistor direction %% @param Pull is the internal resistor state -%% @returns ok | error +%% @returns ok | raise(Error) %% @doc Set the internal resistor of a pin %% %% Pins can be internally pulled `up', `down', `up_down' (pulled in @@ -354,13 +354,13 @@ set_pin_mode(_Pin, _Mode) -> %% or `set_pin_mode/2'. %% @end %%----------------------------------------------------------------------------- --spec set_pin_pull(Pin :: pin(), Pull :: pull()) -> ok | error. +-spec set_pin_pull(Pin :: pin(), Pull :: pull()) -> ok. set_pin_pull(_Pin, _Pull) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- %% @param Pin number of the pin to be held -%% @returns ok | error +%% @returns ok | raise(Error) %% @doc Hold the state of a pin %% %% The gpio pad hold function works in both input and output modes, @@ -380,13 +380,13 @@ set_pin_pull(_Pin, _Pull) -> %% This function is only supported on ESP32. %% @end %%----------------------------------------------------------------------------- --spec hold_en(Pin :: pin()) -> ok | error. +-spec hold_en(Pin :: pin()) -> ok. hold_en(_Pin) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- %% @param Pin number of the pin to be released -%% @returns ok | error +%% @returns ok | raise(Error) %% @doc Release a pin from a hold state. %% %% When the chip is woken up from Deep-sleep, the gpio will be set to @@ -402,7 +402,7 @@ hold_en(_Pin) -> %% This function is only supported on ESP32. %% @end %%----------------------------------------------------------------------------- --spec hold_dis(Pin :: pin()) -> ok | error. +-spec hold_dis(Pin :: pin()) -> ok. hold_dis(_Pin) -> erlang:nif_error(undefined). @@ -445,7 +445,7 @@ deep_sleep_hold_dis() -> %%----------------------------------------------------------------------------- %% @param Pin number of the pin to write %% @param Level the desired output level to set -%% @returns ok | error | {error, Reason} +%% @returns ok | raise(Error) %% @doc Set GPIO digital output level %% %% Set a pin to `high' (1) or `low' (0). @@ -469,13 +469,13 @@ deep_sleep_hold_dis() -> %% require or accept `set_pin_mode' or `set_pin_pull' before use. %% @end %%----------------------------------------------------------------------------- --spec digital_write(Pin :: pin(), Level :: level()) -> ok | {error, Reason :: atom()} | error. +-spec digital_write(Pin :: pin(), Level :: level()) -> ok. digital_write(_Pin, _Level) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- %% @param Pin number of the pin to read -%% @returns high | low | error | {error, Reason} +%% @returns high | low | raise(Error) %% @doc Read the digital state of a GPIO pin %% %% Read if an input pin state is high or low. @@ -486,14 +486,14 @@ digital_write(_Pin, _Level) -> %% and does not require or accept `set_pin_mode' or `set_pin_pull' before use. %% @end %%----------------------------------------------------------------------------- --spec digital_read(Pin :: pin()) -> high | low | {error, Reason :: atom()} | error. +-spec digital_read(Pin :: pin()) -> high | low. digital_read(_Pin) -> erlang:nif_error(undefined). %%----------------------------------------------------------------------------- %% @param Pin number of the pin to set the interrupt on %% @param Trigger is the state that will trigger an interrupt -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Convenience function for `gpio:set_int/3' %% %% This is a convenience function for `gpio:set_int/3' that allows an @@ -509,13 +509,13 @@ digital_read(_Pin) -> %% @end %%----------------------------------------------------------------------------- -spec attach_interrupt(Pin :: pin(), Trigger :: trigger()) -> - ok | {error, Reason :: atom()} | error. + ok | {error, Reason :: atom()}. attach_interrupt(Pin, Trigger) -> set_int(start(), Pin, Trigger). %----------------------------------------------------------------------------- %% @param Pin number of the pin to remove the interrupt -%% @returns ok | error | {error, Reason} +%% @returns ok | {error, Reason} %% @doc Convenience function for `gpio:remove_int/2' %% %% This is a convenience function for `gpio:remove_int/2' that allows an @@ -527,6 +527,6 @@ attach_interrupt(Pin, Trigger) -> %% The rp2040 (Pico) port does not support gpio interrupts at this time. %% @end %%----------------------------------------------------------------------------- --spec detach_interrupt(Pin :: pin()) -> ok | {error, Reason :: atom()} | error. +-spec detach_interrupt(Pin :: pin()) -> ok | {error, Reason :: atom()}. detach_interrupt(Pin) -> remove_int(whereis(gpio), Pin). diff --git a/src/platforms/esp32/components/avm_builtins/gpio_driver.c b/src/platforms/esp32/components/avm_builtins/gpio_driver.c index 49a9c4725..cca84962d 100644 --- a/src/platforms/esp32/components/avm_builtins/gpio_driver.c +++ b/src/platforms/esp32/components/avm_builtins/gpio_driver.c @@ -74,7 +74,9 @@ static const char *const gpio_interrupt_atom = ATOM_STR("\xE", "gpio_interrupt") #endif static const char *const high_atom = ATOM_STR("\x4", "high"); -static const char *const low_atom = ATOM_STR("\x3", "low"); +static const char *const low_atom_str = ATOM_STR("\x3", "low"); +#define HIGH_ATOM globalcontext_make_atom(glb, high_atom) +#define LOW_ATOM globalcontext_make_atom(glb, low_atom_str) static const AtomStringIntPair pin_mode_table[] = { { ATOM_STR("\x5", "input"), GPIO_MODE_INPUT }, @@ -152,29 +154,27 @@ struct GPIOData struct ListHead gpio_listeners; }; -/* TODO: Change error returns to {error, Reason} (See: https://github.com/atomvm/AtomVM/issues/894) */ - static inline term gpio_set_pin_mode(Context *ctx, term gpio_num_term, term mode_term) { gpio_num_t gpio_num; if (LIKELY(term_is_integer(gpio_num_term))) { avm_int_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return BADARG_ATOM; } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return BADARG_ATOM; } avm_int_t mode = interop_atom_term_select_int(pin_mode_table, mode_term, ctx->global); if (UNLIKELY(mode < 0)) { - return ERROR_ATOM; + return BADARG_ATOM; } esp_err_t result = gpio_set_direction(gpio_num, (gpio_mode_t) mode); if (UNLIKELY(result != ESP_OK)) { - return ERROR_ATOM; + return BADARG_ATOM; } return OK_ATOM; @@ -191,21 +191,21 @@ static inline term set_pin_pull_mode(Context *ctx, term gpio_num_term, term pull if (LIKELY(term_is_integer(gpio_num_term))) { avm_int_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return BADARG_ATOM; } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return BADARG_ATOM; } avm_int_t pull_mode = get_pull_mode(ctx, pull); if (UNLIKELY(pull_mode < 0)) { - return ERROR_ATOM; + return BADARG_ATOM; } esp_err_t result = gpio_set_pull_mode(gpio_num, (gpio_pull_mode_t) pull_mode); if (UNLIKELY(result != ESP_OK)) { - return ERROR_ATOM; + return BADARG_ATOM; } return OK_ATOM; } @@ -216,16 +216,16 @@ static inline term hold_en(term gpio_num_term) if (LIKELY(term_is_integer(gpio_num_term))) { avm_int_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return BADARG_ATOM; } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return BADARG_ATOM; } esp_err_t result = gpio_hold_en(gpio_num); if (UNLIKELY(result != ESP_OK)) { - return ERROR_ATOM; + return BADARG_ATOM; } return OK_ATOM; } @@ -236,16 +236,16 @@ static inline term hold_dis(term gpio_num_term) if (LIKELY(term_is_integer(gpio_num_term))) { avm_int_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return BADARG_ATOM; } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return BADARG_ATOM; } esp_err_t result = gpio_hold_dis(gpio_num); if (UNLIKELY(result != ESP_OK)) { - return ERROR_ATOM; + return BADARG_ATOM; } return OK_ATOM; } @@ -256,54 +256,56 @@ static inline term gpio_digital_write(Context *ctx, term gpio_num_term, term lev if (LIKELY(term_is_integer(gpio_num_term))) { avm_int_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return BADARG_ATOM; } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return BADARG_ATOM; } int level; if (term_is_integer(level_term)) { level = term_to_int32(level_term); if (UNLIKELY((level != 0) && (level != 1))) { - return ERROR_ATOM; + return BADARG_ATOM; } } else { level = interop_atom_term_select_int(pin_level_table, level_term, ctx->global); if (UNLIKELY(level < 0)) { - return ERROR_ATOM; + return BADARG_ATOM; } } esp_err_t result = gpio_set_level(gpio_num, level); if (UNLIKELY(result != ESP_OK)) { - return ERROR_ATOM; + return BADARG_ATOM; } return OK_ATOM; } -static inline term gpio_digital_read(term gpio_num_term) +static inline term gpio_digital_read(Context *ctx, term gpio_num_term) { + GlobalContext *glb = ctx->global; gpio_num_t gpio_num; if (LIKELY(term_is_integer(gpio_num_term))) { avm_int_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return BADARG_ATOM; } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return BADARG_ATOM; } avm_int_t level = gpio_get_level(gpio_num); - return level ? globalcontext_make_atom(glb, high_atom) : globalcontext_make_atom(glb, low_atom); + return level ? HIGH_ATOM : LOW_ATOM; } #ifdef CONFIG_AVM_ENABLE_GPIO_PORT_DRIVER + void gpio_driver_init(GlobalContext *global) { int index = globalcontext_insert_atom(global, gpio_driver_atom); @@ -342,7 +344,7 @@ static term gpiodriver_close(Context *ctx) GlobalContext *glb = ctx->global; int gpio_atom_index = atom_table_ensure_atom(glb->atom_table, gpio_atom, AtomTableNoOpts); if (UNLIKELY(!globalcontext_get_registered_process(glb, gpio_atom_index))) { - return ERROR_ATOM; + return port_create_error_tuple(ctx, NOPROC_ATOM); } struct GPIOData *gpio_data = ctx->platform_data; @@ -399,7 +401,11 @@ static term gpiodriver_set_level(Context *ctx, term cmd) term gpio_num = term_get_tuple_element(cmd, 1); term level = term_get_tuple_element(cmd, 2); - return gpio_digital_write(ctx, gpio_num, level); + term result = gpio_digital_write(ctx, gpio_num, level); + if (UNLIKELY(result != OK_ATOM)) { + return port_create_error_tuple(ctx, result); + } + return result; } static term gpiodriver_set_direction(Context *ctx, term cmd) @@ -407,13 +413,21 @@ static term gpiodriver_set_direction(Context *ctx, term cmd) term gpio_num = term_get_tuple_element(cmd, 1); term direction = term_get_tuple_element(cmd, 2); - return gpio_set_pin_mode(ctx, gpio_num, direction); + term result = gpio_set_pin_mode(ctx, gpio_num, direction); + if (UNLIKELY(result != OK_ATOM)) { + return port_create_error_tuple(ctx, result); + } + return result; } -static term gpiodriver_read(term cmd) +static term gpiodriver_read(Context *ctx, term cmd) { term gpio_num = term_get_tuple_element(cmd, 1); - return gpio_digital_read(gpio_num); + term result = gpio_digital_read(ctx, gpio_num); + if (UNLIKELY(result == BADARG_ATOM)) { + return port_create_error_tuple(ctx, result); + } + return result; } static bool gpiodriver_is_gpio_attached(struct GPIOData *gpio_data, int gpio_num) @@ -451,7 +465,7 @@ static term unregister_interrupt_listener(Context *ctx, gpio_num_t gpio_num) } } - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) @@ -466,11 +480,11 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) if (LIKELY(term_is_integer(gpio_num_term))) { int32_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } term trigger = term_get_tuple_element(cmd, 2); @@ -478,7 +492,7 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) term pid = term_get_tuple_element(cmd, 3); if (UNLIKELY(!term_is_pid(pid) && !term_is_atom(pid))) { ESP_LOGE(TAG, "Invalid listener parameter, must be a pid() or registered process!"); - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } if (term_is_pid(pid)) { target_local_pid = term_to_local_process_id(pid); @@ -487,7 +501,7 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) int32_t registered_process = (int32_t) globalcontext_get_registered_process(ctx->global, pid_atom_index); if (UNLIKELY(registered_process == 0)) { ESP_LOGE(TAG, "Invalid listener parameter, atom() is not a registered process name!"); - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } target_local_pid = registered_process; } @@ -497,12 +511,13 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) gpio_int_type_t interrupt_type = interop_atom_term_select_int(int_trigger_table, trigger, ctx->global); if(UNLIKELY(interrupt_type == GPIO_INTR_MAX)) { - return BADARG_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } if (trigger != NONE_ATOM) { if (UNLIKELY(gpiodriver_is_gpio_attached(gpio_data, gpio_num))) { - return ERROR_ATOM; + ESP_LOGE(TAG, "Pin %i already attached to interrupt", gpio_num); + return port_create_error_tuple(ctx, BADARG_ATOM); } TRACE("going to install interrupt for %i.\n", gpio_num); @@ -515,7 +530,7 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) struct GPIOListenerData *data = malloc(sizeof(struct GPIOListenerData)); if (IS_NULL_PTR(data)) { ESP_LOGE(TAG, "gpiodriver_set_int: Failed to ensure free heap space."); - AVM_ABORT(); + return port_create_error_tuple(ctx, OUT_OF_MEMORY_ATOM); } list_append(&gpio_data->gpio_listeners, &data->gpio_listener_list_head); data->gpio = gpio_num; @@ -524,16 +539,22 @@ static term gpiodriver_set_int(Context *ctx, int32_t target_pid, term cmd) data->listener.sender = data; data->listener.handler = gpio_interrupt_callback; - gpio_set_direction(gpio_num, GPIO_MODE_INPUT); - gpio_set_intr_type(gpio_num, interrupt_type); - - esp_err_t ret = gpio_isr_handler_add(gpio_num, gpio_isr_handler, data); + // These inputs have already been validated, so any errors indicate a bad state or internal error. + esp_err_t ret = gpio_set_direction(gpio_num, GPIO_MODE_INPUT); if (UNLIKELY(ret != ESP_OK)) { - return ERROR_ATOM; + return port_create_error_tuple(ctx, globalcontext_make_atom(ctx->global, ATOM_STR("\xF", "direction_state"))); + } + ret = gpio_set_intr_type(gpio_num, interrupt_type); + if (UNLIKELY(ret != ESP_OK)) { + return port_create_error_tuple(ctx, globalcontext_make_atom(ctx->global, ATOM_STR("\xF", "interrupt_state"))); + } + ret = gpio_isr_handler_add(gpio_num, gpio_isr_handler, data); + if (UNLIKELY(ret != ESP_OK)) { + return port_create_error_tuple(ctx, globalcontext_make_atom(ctx->global, ATOM_STR("\xD", "handler_state"))); } } else { if (UNLIKELY(!gpiodriver_is_gpio_attached(gpio_data, gpio_num))) { - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } gpio_set_intr_type(gpio_num, interrupt_type); return unregister_interrupt_listener(ctx, gpio_num); @@ -549,11 +570,11 @@ static term gpiodriver_remove_int(Context *ctx, term cmd) if (LIKELY(term_is_integer(gpio_num_term))) { int32_t pin_int = term_to_int32(gpio_num_term); if (UNLIKELY((pin_int < 0) || (pin_int >= GPIO_NUM_MAX))) { - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } gpio_num = (gpio_num_t) pin_int; } else { - return ERROR_ATOM; + return port_create_error_tuple(ctx, BADARG_ATOM); } @@ -596,7 +617,7 @@ static NativeHandlerResult consume_gpio_mailbox(Context *ctx) break; case GPIOReadCmd: - ret = gpiodriver_read(gen_message.req); + ret = gpiodriver_read(ctx, gen_message.req); break; case GPIOSetIntCmd: @@ -613,12 +634,12 @@ static NativeHandlerResult consume_gpio_mailbox(Context *ctx) default: ESP_LOGW(TAG, "Unrecognized command"); - ret = ERROR_ATOM; + ret = port_create_error_tuple(ctx, BADARG_ATOM); } term ret_msg; if (UNLIKELY(memory_ensure_free_with_roots(ctx, 3, 1, &ret, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { - ret_msg = OUT_OF_MEMORY_ATOM; + ret_msg = port_create_error_tuple(ctx, OUT_OF_MEMORY_ATOM); } else { ret_msg = create_pair(ctx, gen_message.ref, ret); } @@ -675,20 +696,28 @@ static term nif_gpio_init(Context *ctx, int argc, term argv[]) return OK_ATOM; } -/* TODO: in the case of {error, Return} we should RAISE_ERROR(Reason) */ - static term nif_gpio_set_pin_mode(Context *ctx, int argc, term argv[]) { UNUSED(argc); - return gpio_set_pin_mode(ctx, argv[0], argv[1]); + term result = gpio_set_pin_mode(ctx, argv[0], argv[1]); + if (UNLIKELY(result != OK_ATOM)) { + RAISE_ERROR(result); + } + + return result; } static term nif_gpio_set_pin_pull(Context *ctx, int argc, term argv[]) { UNUSED(argc); - return set_pin_pull_mode(ctx, argv[0], argv[1]); + term result = set_pin_pull_mode(ctx, argv[0], argv[1]); + if (UNLIKELY(result != OK_ATOM)) { + RAISE_ERROR(result); + } + + return result; } static term nif_gpio_hold_en(Context *ctx, int argc, term argv[]) @@ -696,7 +725,12 @@ static term nif_gpio_hold_en(Context *ctx, int argc, term argv[]) UNUSED(ctx); UNUSED(argc); - return hold_en(argv[0]); + term result = hold_en(argv[0]); + if (UNLIKELY(result != OK_ATOM)) { + RAISE_ERROR(result); + } + + return result; } static term nif_gpio_hold_dis(Context *ctx, int argc, term argv[]) @@ -704,7 +738,12 @@ static term nif_gpio_hold_dis(Context *ctx, int argc, term argv[]) UNUSED(ctx); UNUSED(argc); - return hold_dis(argv[0]); + term result = hold_dis(argv[0]); + if (UNLIKELY(result != OK_ATOM)) { + RAISE_ERROR(result); + } + + return result; } #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 2) && SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 2) && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP) @@ -731,7 +770,11 @@ static term nif_gpio_deep_sleep_hold_dis(Context *ctx, int argc, term argv[]) static term nif_gpio_digital_write(Context *ctx, int argc, term argv[]) { - return gpio_digital_write(ctx, argv[0], argv[1]); + term result = gpio_digital_write(ctx, argv[0], argv[1]); + if (UNLIKELY(result != OK_ATOM)) { + RAISE_ERROR(result); + } + return result; } static term nif_gpio_digital_read(Context *ctx, int argc, term argv[])