Skip to content

Commit

Permalink
Merge pull request #1307 from realglobe-Inc/fix/uart
Browse files Browse the repository at this point in the history
Fix broken `uart` module

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later

`uart` module for ESP32 is broken. This PR fixes it.

* In the current code, `uart:open/1,2` takes `uart0`, `uart1` or `uart2` as
`peripheral` option. However, Nif takes either one of `UART0`, `UART1` or
`UART2`. This PR corrects the behaviour of `uart:open` to match that of Nif.
* The Nif of `uart` module does not send a reply parsable by `port:call`, which
stops the process from executing further codes. This PR fixes that by using
`port_send_reply` function.
  • Loading branch information
bettio committed Oct 10, 2024
2 parents 9be487f + afe8e02 commit ff34010
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ instead
`network:start/1`, that would lead to a hard crash of the VM.
- Fix a bug in ESP32 network driver where the low level driver was not being stopped and resoureces were not freed
when `network:stop/0` was used, see issue [#643](https://github.com/atomvm/AtomVM/issues/643)
- `uart:open/1,2` now works with uppercase peripheral names

## [0.6.4] - 2024-08-18

Expand Down
10 changes: 4 additions & 6 deletions libs/eavmlib/src/uart.erl
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,15 @@ warn_deprecated(OldKey, NewKey) ->
validate_peripheral(I) when is_integer(I) ->
io:format("UART: deprecated integer peripheral is used.~n"),
I;
validate_peripheral([$u, $a, $r, $t | N] = Value) ->
validate_peripheral([$U, $A, $R, $T | N] = Value) ->
try list_to_integer(N) of
% Internally integers are still used
% TODO: change this as soon as ESP32 code is reworked
I -> I
_ -> Value
catch
error:_ -> {bardarg, {peripheral, Value}}
end;
validate_peripheral(<<"uart", N/binary>> = Value) ->
validate_peripheral(<<"UART", N/binary>> = Value) ->
try binary_to_integer(N) of
I -> I
_ -> Value
catch
error:_ -> {bardarg, {peripheral, Value}}
end;
Expand Down
67 changes: 22 additions & 45 deletions src/platforms/esp32/components/avm_builtins/uart_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,13 +298,12 @@ Context *uart_driver_create_port(GlobalContext *global, term opts)
return ctx;
}

static void uart_driver_do_read(Context *ctx, term msg)
static void uart_driver_do_read(Context *ctx, GenMessage gen_message)
{
GlobalContext *glb = ctx->global;
struct UARTData *uart_data = ctx->platform_data;

term pid = term_get_tuple_element(msg, 0);
term ref = term_get_tuple_element(msg, 1);
term pid = gen_message.pid;
term ref = gen_message.ref;
uint64_t ref_ticks = term_to_ref_ticks(ref);

int local_pid = term_to_local_process_id(pid);
Expand All @@ -313,20 +312,12 @@ static void uart_driver_do_read(Context *ctx, term msg)
if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2) * 2 + REF_SIZE) != MEMORY_GC_OK)) {
ESP_LOGE(TAG, "[uart_driver_do_read] Failed to allocate space for error tuple");
globalcontext_send_message(glb, local_pid, MEMORY_ATOM);
return;
}

term ealready = globalcontext_make_atom(glb, ealready_atom);

term error_tuple = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(error_tuple, 0, ERROR_ATOM);
term_put_tuple_element(error_tuple, 1, ealready);

term result_tuple = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(result_tuple, 0, term_from_ref_ticks(ref_ticks, &ctx->heap));
term_put_tuple_element(result_tuple, 1, error_tuple);

globalcontext_send_message(glb, local_pid, result_tuple);

term error_tuple = port_create_error_tuple(ctx, ealready);
port_send_reply(ctx, pid, ref, error_tuple);
return;
}

Expand All @@ -348,30 +339,24 @@ static void uart_driver_do_read(Context *ctx, term msg)
term_put_tuple_element(ok_tuple, 0, OK_ATOM);
term_put_tuple_element(ok_tuple, 1, bin);

term result_tuple = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(result_tuple, 0, term_from_ref_ticks(ref_ticks, &ctx->heap));
term_put_tuple_element(result_tuple, 1, ok_tuple);

globalcontext_send_message(glb, local_pid, result_tuple);
port_send_reply(ctx, pid, ref, ok_tuple);

} else {
uart_data->reader_process_pid = pid;
uart_data->reader_ref_ticks = ref_ticks;
}
}

static void uart_driver_do_write(Context *ctx, term msg)
static void uart_driver_do_write(Context *ctx, GenMessage gen_message)
{
GlobalContext *glb = ctx->global;
struct UARTData *uart_data = ctx->platform_data;
term msg = gen_message.req;
term pid = gen_message.pid;
term ref = gen_message.ref;

term pid = term_get_tuple_element(msg, 0);
term ref = term_get_tuple_element(msg, 1);
uint64_t ref_ticks = term_to_ref_ticks(ref);

term cmd = term_get_tuple_element(msg, 2);

term data = term_get_tuple_element(cmd, 1);
term cmd = term_get_tuple_element(msg, 0);
term data = term_get_tuple_element(msg, 1);

size_t buffer_size;
switch (interop_iolist_size(data, &buffer_size)) {
Expand Down Expand Up @@ -408,21 +393,16 @@ static void uart_driver_do_write(Context *ctx, term msg)
globalcontext_send_message(glb, local_pid, MEMORY_ATOM);
}

term result_tuple = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(result_tuple, 0, term_from_ref_ticks(ref_ticks, &ctx->heap));
term_put_tuple_element(result_tuple, 1, OK_ATOM);

globalcontext_send_message(glb, local_pid, result_tuple);
port_send_reply(ctx, pid, ref, OK_ATOM);
}

static void uart_driver_do_close(Context *ctx, term msg)
static void uart_driver_do_close(Context *ctx, GenMessage gen_message)
{
GlobalContext *glb = ctx->global;
struct UARTData *uart_data = ctx->platform_data;

term pid = term_get_tuple_element(msg, 0);
term ref = term_get_tuple_element(msg, 1);
uint64_t ref_ticks = term_to_ref_ticks(ref);
term msg = gen_message.req;
term pid = gen_message.pid;
term ref = gen_message.ref;

int local_pid = term_to_local_process_id(pid);

Expand All @@ -433,10 +413,7 @@ static void uart_driver_do_close(Context *ctx, term msg)
globalcontext_send_message(glb, local_pid, MEMORY_ATOM);
}

term result_tuple = term_alloc_tuple(2, &ctx->heap);
term_put_tuple_element(result_tuple, 0, term_from_ref_ticks(ref_ticks, &ctx->heap));
term_put_tuple_element(result_tuple, 1, OK_ATOM);
globalcontext_send_message(glb, local_pid, result_tuple);
port_send_reply(ctx, pid, ref, OK_ATOM);

esp_err_t err = uart_driver_delete(uart_data->uart_num);
if (UNLIKELY(err != ESP_OK)) {
Expand Down Expand Up @@ -492,17 +469,17 @@ static NativeHandlerResult uart_driver_consume_mailbox(Context *ctx)
switch (cmd) {
case UARTReadCmd:
TRACE("read\n");
uart_driver_do_read(ctx, msg);
uart_driver_do_read(ctx, gen_message);
break;

case UARTWriteCmd:
TRACE("write\n");
uart_driver_do_write(ctx, msg);
uart_driver_do_write(ctx, gen_message);
break;

case UARTCloseCmd:
TRACE("close\n");
uart_driver_do_close(ctx, msg);
uart_driver_do_close(ctx, gen_message);
is_closed = true;
break;

Expand Down

0 comments on commit ff34010

Please sign in to comment.