Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

port: add helper function for parsing message tuple #997

Merged
merged 2 commits into from
Dec 26, 2023
Merged
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
1 change: 0 additions & 1 deletion doc/src/apidocs/libatomvm/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ Functions
.. doxygenfunction:: port_heap_create_tuple2
.. doxygenfunction:: port_heap_create_tuple3
.. doxygenfunction:: port_heap_create_tuple_n
.. doxygenfunction:: port_is_standard_port_command
.. doxygenfunction:: port_send_message
.. doxygenfunction:: port_send_message_nolock
.. doxygenfunction:: posix_errno_to_term
Expand Down
11 changes: 6 additions & 5 deletions src/libAtomVM/nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,8 @@ static NativeHandlerResult process_console_message(Context *ctx, term msg)
AVM_ABORT();
}

GenMessage gen_message;

if (term_is_tuple(msg) && term_get_tuple_arity(msg) == 2 && term_get_tuple_element(msg, 1) == CLOSE_ATOM) {
result = NativeTerminate;
term pid = term_get_tuple_element(msg, 0);
Expand Down Expand Up @@ -1032,11 +1034,10 @@ static NativeHandlerResult process_console_message(Context *ctx, term msg)
}
}

} else if (port_is_standard_port_command(msg)) {

term pid = term_get_tuple_element(msg, 0);
term ref = term_get_tuple_element(msg, 1);
term cmd = term_get_tuple_element(msg, 2);
} else if (port_parse_gen_message(msg, &gen_message) == GenCallMessage) {
term pid = gen_message.pid;
term ref = gen_message.ref;
term cmd = gen_message.req;

if (term_is_atom(cmd) && cmd == FLUSH_ATOM) {
fflush(stdout);
Expand Down
40 changes: 21 additions & 19 deletions src/libAtomVM/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,6 @@ void port_ensure_available(Context *ctx, size_t size)
}
}

int port_is_standard_port_command(term t)
{
if (!term_is_tuple(t)) {
return 0;
} else if (term_get_tuple_arity(t) != 3) {
return 0;
} else {
term pid = term_get_tuple_element(t, 0);
term ref = term_get_tuple_element(t, 1);
if (!term_is_pid(pid)) {
return 0;
} else if (!term_is_reference(ref)) {
return 0;
} else {
return 1;
}
}
}

term port_heap_create_tuple2(Heap *heap, term a, term b)
{
term terms[2];
Expand Down Expand Up @@ -123,3 +104,24 @@ term port_heap_create_reply(Heap *heap, term ref, term payload)
{
return port_heap_create_tuple2(heap, ref, payload);
}

enum GenMessageParseResult port_parse_gen_message(term msg, GenMessage *gen_message)
{
if (UNLIKELY(!term_is_tuple(msg) || term_get_tuple_arity(msg) != 3)) {
return GenMessageParseError;
}

gen_message->pid = term_get_tuple_element(msg, 0);
if (UNLIKELY(!term_is_pid(gen_message->pid))) {
return GenMessageParseError;
}

gen_message->ref = term_get_tuple_element(msg, 1);
if (UNLIKELY(!term_is_reference(gen_message->ref))) {
return GenMessageParseError;
}

gen_message->req = term_get_tuple_element(msg, 2);

return GenCallMessage;
}
17 changes: 16 additions & 1 deletion src/libAtomVM/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ static inline term port_create_reply(Context *ctx, term ref, term payload)
void port_send_message(GlobalContext *glb, term pid, term msg);
void port_send_message_nolock(GlobalContext *glb, term pid, term msg);
void port_ensure_available(Context *ctx, size_t size);
int port_is_standard_port_command(term msg);

// Helper to send a message from NIFs or from the native handler.
static inline void port_send_reply(Context *ctx, term pid, term ref, term payload)
Expand All @@ -83,6 +82,22 @@ static inline void port_send_reply(Context *ctx, term pid, term ref, term payloa
port_send_message(ctx->global, pid, reply);
}

typedef struct
{
term req;

term pid;
term ref;
} GenMessage;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not all messages will have a ref or even a pid. Are we okay with this? I am fine with it, and I consider this a kind of interim solution, so that's fine. Just thinking ahead to what an $info or $cast message would look like.

This is just an observation, not a change request.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In that case GenCastMessage instead of GenCallMessage will be returned (pid and ref will be invalid).


enum GenMessageParseResult
{
GenCallMessage,
GenMessageParseError
};

enum GenMessageParseResult port_parse_gen_message(term msg, GenMessage *gen_message);

#ifdef __cplusplus
}
#endif
Expand Down
28 changes: 16 additions & 12 deletions src/platforms/esp32/components/avm_builtins/gpio_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "module.h"
#include "nifs.h"
#include "platform_defaultatoms.h"
#include "port.h"
#include "scheduler.h"
#include "term.h"
#include "utils.h"
Expand Down Expand Up @@ -477,35 +478,39 @@ static term create_pair(Context *ctx, term term1, term term2)
static NativeHandlerResult consume_gpio_mailbox(Context *ctx)
{
Message *message = mailbox_first(&ctx->mailbox);
term msg = message->message;
term pid = term_get_tuple_element(msg, 0);
term req = term_get_tuple_element(msg, 2);
term cmd_term = term_get_tuple_element(req, 0);
GenMessage gen_message;
if (UNLIKELY(port_parse_gen_message(message->message, &gen_message) != GenCallMessage)) {
ESP_LOGW(TAG, "Received invalid message.");
mailbox_remove_message(&ctx->mailbox, &ctx->heap);
return NativeContinue;
}

term cmd_term = term_get_tuple_element(gen_message.req, 0);

int local_process_id = term_to_local_process_id(pid);
int local_process_id = term_to_local_process_id(gen_message.pid);

term ret;

enum gpio_cmd cmd = interop_atom_term_select_int(gpio_cmd_table, cmd_term, ctx->global);
switch (cmd) {
case GPIOSetLevelCmd:
ret = gpiodriver_set_level(ctx, req);
ret = gpiodriver_set_level(ctx, gen_message.req);
break;

case GPIOSetDirectionCmd:
ret = gpiodriver_set_direction(ctx, req);
ret = gpiodriver_set_direction(ctx, gen_message.req);
break;

case GPIOReadCmd:
ret = gpiodriver_read(req);
ret = gpiodriver_read(gen_message.req);
break;

case GPIOSetIntCmd:
ret = gpiodriver_set_int(ctx, local_process_id, req);
ret = gpiodriver_set_int(ctx, local_process_id, gen_message.req);
break;

case GPIORemoveIntCmd:
ret = gpiodriver_remove_int(ctx, req);
ret = gpiodriver_remove_int(ctx, gen_message.req);
break;

case GPIOCloseCmd:
Expand All @@ -521,8 +526,7 @@ static NativeHandlerResult consume_gpio_mailbox(Context *ctx)
if (UNLIKELY(memory_ensure_free_with_roots(ctx, 3, 1, &ret, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
ret_msg = OUT_OF_MEMORY_ATOM;
} else {
term ref = term_get_tuple_element(msg, 1);
ret_msg = create_pair(ctx, ref, ret);
ret_msg = create_pair(ctx, gen_message.ref, ret);
}

globalcontext_send_message(ctx->global, local_process_id, ret_msg);
Expand Down
30 changes: 16 additions & 14 deletions src/platforms/esp32/components/avm_builtins/i2c_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -546,45 +546,48 @@ static term create_pair(Context *ctx, term term1, term term2)
static NativeHandlerResult i2cdriver_consume_mailbox(Context *ctx)
{
Message *message = mailbox_first(&ctx->mailbox);
term msg = message->message;
term pid = term_get_tuple_element(msg, 0);
term req = term_get_tuple_element(msg, 2);
GenMessage gen_message;
if (UNLIKELY(port_parse_gen_message(message->message, &gen_message) != GenCallMessage)) {
ESP_LOGW(TAG, "Received invalid message.");
mailbox_remove_message(&ctx->mailbox, &ctx->heap);
return NativeContinue;
}

#ifdef ENABLE_TRACE
TRACE("message: ");
term_display(stdout, msg, ctx);
TRACE("\n");
#endif

term cmd_term = term_get_tuple_element(req, 0);
term cmd_term = term_get_tuple_element(gen_message.req, 0);

int local_process_id = term_to_local_process_id(pid);
int local_process_id = term_to_local_process_id(gen_message.pid);

term ret;

enum i2c_cmd cmd = interop_atom_term_select_int(cmd_table, cmd_term, ctx->global);
switch (cmd) {
case I2CBeginTransmissionCmd:
ret = i2cdriver_begin_transmission(ctx, pid, req);
ret = i2cdriver_begin_transmission(ctx, gen_message.pid, gen_message.req);
break;

case I2CEndTransmissionCmd:
ret = i2cdriver_end_transmission(ctx, pid);
ret = i2cdriver_end_transmission(ctx, gen_message.pid);
break;

case I2CWriteByteCmd:
ret = i2cdriver_write_byte(ctx, pid, req);
ret = i2cdriver_write_byte(ctx, gen_message.pid, gen_message.req);
break;

case I2CReadBytesCmd:
ret = i2cdriver_read_bytes(ctx, pid, req);
ret = i2cdriver_read_bytes(ctx, gen_message.pid, gen_message.req);
break;

case I2CWriteBytesCmd:
if (term_get_tuple_arity(req) == 2) {
ret = i2cdriver_qwrite_bytes(ctx, pid, req);
if (term_get_tuple_arity(gen_message.req) == 2) {
ret = i2cdriver_qwrite_bytes(ctx, gen_message.pid, gen_message.req);
} else {
ret = i2cdriver_write_bytes(ctx, pid, req);
ret = i2cdriver_write_bytes(ctx, gen_message.pid, gen_message.req);
}
break;
case I2CCloseCmd:
Expand All @@ -601,8 +604,7 @@ static NativeHandlerResult i2cdriver_consume_mailbox(Context *ctx)
if (UNLIKELY(memory_ensure_free_with_roots(ctx, 3, 1, &ret, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
ret_msg = OUT_OF_MEMORY_ATOM;
} else {
term ref = term_get_tuple_element(msg, 1);
ret_msg = create_pair(ctx, ref, ret);
ret_msg = create_pair(ctx, gen_message.ref, ret);
}

globalcontext_send_message(ctx->global, local_process_id, ret_msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,7 @@ static NativeHandlerResult consume_mailbox(Context *ctx)
return NativeContinue;
}

//TODO: port this code to standard port (and gen_message)
term pid = term_get_tuple_element(msg, 0);
term ref = term_get_tuple_element(msg, 1);
term cmd = term_get_tuple_element(msg, 2);
Expand Down
Loading