From 069fcc5de1de6333374aecdbb6fcc0c9823d5e0c Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 1 Sep 2017 08:43:21 +0200 Subject: [PATCH 01/17] sys: js: initial commit of javascript support module --- Makefile.dep | 6 +++ sys/include/js.h | 46 ++++++++++++++++ sys/js/Makefile | 1 + sys/js/init.c | 23 ++++++++ sys/js/js.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++ sys/js/riot.c | 19 +++++++ sys/js/timer.c | 86 +++++++++++++++++++++++++++++ 7 files changed, 318 insertions(+) create mode 100644 sys/include/js.h create mode 100644 sys/js/Makefile create mode 100644 sys/js/init.c create mode 100644 sys/js/js.c create mode 100644 sys/js/riot.c create mode 100644 sys/js/timer.c diff --git a/Makefile.dep b/Makefile.dep index 3323dbb0269a..b9604b07317e 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -715,6 +715,12 @@ USEPKG += nanocoap USEMODULE += gnrc_sock_udp endif +ifneq (,$(filter js,$(USEMODULE))) + USEPKG += jerryscript + USEMODULE += xtimer + USEMODULE += event +endif + # always select gpio (until explicit dependencies are sorted out) FEATURES_OPTIONAL += periph_gpio diff --git a/sys/include/js.h b/sys/include/js.h new file mode 100644 index 000000000000..74c0b3b721e7 --- /dev/null +++ b/sys/include/js.h @@ -0,0 +1,46 @@ +#ifndef JS_H +#define JS_H + +#include "event.h" +#include "jerryscript.h" +#include "jerryscript-ext/handler.h" + +extern event_queue_t *js_event_queue; + +typedef struct { + const char *name; + jerry_external_handler_t handler; +} js_native_method_t; + +typedef struct { + const char *name; + const js_native_method_t *methods; +} js_native_objects_t; + +typedef struct { + event_t event; + jerry_value_t callback; + jerry_value_t object; +} js_callback_t; + +void js_init(event_queue_t *queue); +int js_run(const jerry_char_t *script, size_t script_size); + +/* internal */ +void js_init_objects(void); +void js_add_object(jerry_value_t object, jerry_value_t other, const char *name); +void *js_get_object_native_pointer(jerry_value_t object, const jerry_object_native_info_t *type); +jerry_value_t js_object_create_with_methods(const js_native_method_t *methods, unsigned num_methods); +jerry_value_t js_object_native_create(size_t size, const jerry_object_native_info_t *native_obj_type_info); +void js_callback(void *arg); +void js_event_callback(event_t *event); +void js_run_callback(jerry_value_t callback); + +#define JS_EXTERNAL_HANDLER(name) \ + jerry_value_t \ + js_external_handler_ ## name (const jerry_value_t func_value, \ + const jerry_value_t this_value, \ + const jerry_value_t * args_p, \ + const jerry_length_t args_cnt) + +#endif /* JS_H */ diff --git a/sys/js/Makefile b/sys/js/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/sys/js/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/js/init.c b/sys/js/init.c new file mode 100644 index 000000000000..1ae151c21826 --- /dev/null +++ b/sys/js/init.c @@ -0,0 +1,23 @@ +#include "event.h" +#include "js.h" + +extern const js_native_method_t timer_methods[]; +extern const unsigned timer_methods_len; + +extern const js_native_method_t riot_methods[]; +extern const unsigned riot_methods_len; + +void js_init_objects(void) +{ + jerry_value_t global_object = jerry_get_global_object(); + + jerry_value_t riot_object = js_object_create_with_methods(riot_methods, riot_methods_len); + js_add_object(global_object, riot_object, "riot"); + jerry_release_value(riot_object); + + jerry_value_t timer_object = js_object_create_with_methods(timer_methods, timer_methods_len); + js_add_object(global_object, timer_object, "timer"); + jerry_release_value(timer_object); + + jerry_release_value(global_object); +} diff --git a/sys/js/js.c b/sys/js/js.c new file mode 100644 index 000000000000..1011f18eaa4e --- /dev/null +++ b/sys/js/js.c @@ -0,0 +1,137 @@ +#include +#include +#include + +#include "js.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +event_queue_t *js_event_queue; + +void js_add_external_handler(jerry_value_t object, const char *name, jerry_external_handler_t handler) +{ + /* Create a JS function object and wrap into a jerry value */ + jerry_value_t func_obj = jerry_create_external_function(handler); + + /* Set the native function as a property of the empty JS object */ + jerry_value_t prop_name = jerry_create_string((const jerry_char_t *) name); + + jerry_release_value(jerry_set_property(object, prop_name, func_obj)); + jerry_release_value(prop_name); + jerry_release_value(func_obj); +} + +void js_add_object(jerry_value_t object, jerry_value_t other, const char *name) +{ + jerry_value_t prop_name = jerry_create_string((const jerry_char_t *) name); + + jerry_release_value(jerry_set_property(object, prop_name, other)); + jerry_release_value(prop_name); +} + +jerry_value_t js_object_native_create(size_t size, const jerry_object_native_info_t *native_obj_type_info) +{ + jerry_value_t object = jerry_create_object(); + void *native_obj = malloc(size); + + if (!native_obj) { + printf("%s(): malloc failed\n", __func__); + } + jerry_set_object_native_pointer(object, native_obj, native_obj_type_info); + return object; +} + +void *js_get_object_native_pointer(jerry_value_t object, const jerry_object_native_info_t *type) +{ + void *result; + const jerry_object_native_info_t *type_tmp; + + bool has_p = jerry_get_object_native_pointer(object, &result, &type_tmp); + + return (has_p && (type_tmp == type)) ? result : NULL; +} + +jerry_value_t js_object_create_with_methods(const js_native_method_t *methods, unsigned num_methods) +{ + jerry_value_t object = jerry_create_object(); + + for (unsigned n = 0; n < num_methods; n++) { + const js_native_method_t *method = methods++; + js_add_external_handler(object, method->name, method->handler); + } + + return object; +} + +void js_run_callback(jerry_value_t callback) +{ + if (jerry_value_is_function(callback)) { + jerry_value_t this_val = jerry_create_undefined(); + jerry_value_t ret_val = jerry_call_function(callback, this_val, NULL, 0); + + if (!jerry_value_has_error_flag(ret_val)) { + DEBUG("%s():l%u %s\n", __FILE__, __LINE__, __func__); + } + else { + printf("%s():l%u %s\n", __FILE__, __LINE__, __func__); + } + + jerry_release_value(ret_val); + jerry_release_value(this_val); + } + else { + printf("%s():l%u %s\n", __FILE__, __LINE__, __func__); + } + jerry_release_value(callback); +} + +void js_callback(void *arg) +{ + js_callback_t *js_callback = (js_callback_t *)arg; + event_post(js_event_queue, &js_callback->event); +} + +void js_event_callback(event_t *event) +{ + js_callback_t *js_callback = (js_callback_t *) event; + js_run_callback(js_callback->callback); + jerry_release_value(js_callback->object); +} + +int js_run(const jerry_char_t *script, size_t script_size) +{ + jerry_value_t ret_value; + + /* Setup Global scope code */ + ret_value = jerry_parse(script, script_size, false); + + if (!jerry_value_has_error_flag(ret_value)) { + /* Execute the parsed source code in the Global scope */ + ret_value = jerry_run(ret_value); + } + + int res = 0; + + if (jerry_value_has_error_flag(ret_value)) { + puts("js_run(): Script Error!"); + res = -1; + } + + jerry_release_value(ret_value); + + return res; +} + +void js_init(event_queue_t *queue) +{ + js_event_queue = queue; + + /* Initialize engine */ + jerry_init(JERRY_INIT_EMPTY); + + /* Register the print function in the global object. */ + jerryx_handler_register_global((const jerry_char_t *) "print", jerryx_handler_print); + + js_init_objects(); +} diff --git a/sys/js/riot.c b/sys/js/riot.c new file mode 100644 index 000000000000..df235b17c000 --- /dev/null +++ b/sys/js/riot.c @@ -0,0 +1,19 @@ +#include "js.h" +#include "periph/pm.h" + +static JS_EXTERNAL_HANDLER(reboot) { + (void)func_value; + (void)this_value; + (void)args_p; + (void)args_cnt; + + pm_reboot(); + + return 0; +} + +const js_native_method_t riot_methods[] = { + { "reboot", js_external_handler_reboot } +}; + +const unsigned riot_methods_len = sizeof(riot_methods)/sizeof(riot_methods[0]); diff --git a/sys/js/timer.c b/sys/js/timer.c new file mode 100644 index 000000000000..81f0d0387eae --- /dev/null +++ b/sys/js/timer.c @@ -0,0 +1,86 @@ +#include +#include +#include + +#include "event.h" +#include "js.h" +#include "xtimer.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +typedef struct { + js_callback_t callback; + xtimer_t xtimer; +} js_xtimer_t; + +static void _js_xtimer_freecb(void *native_p) +{ + DEBUG("%s:l%u:%s()\n", __FILE__, __LINE__, __func__); + + js_xtimer_t *js_xtimer = (js_xtimer_t *) native_p; + xtimer_remove(&js_xtimer->xtimer); + free(js_xtimer); +} + +static const jerry_object_native_info_t js_xtimer_object_native_info = +{ + .free_cb = _js_xtimer_freecb +}; + +static jerry_value_t js_xtimer_create(jerry_value_t callback, uint32_t timeout) +{ + jerry_value_t object = js_object_native_create(sizeof(js_xtimer_t), &js_xtimer_object_native_info); + js_xtimer_t *js_xtimer = js_get_object_native_pointer(object, &js_xtimer_object_native_info); + + if (!js_xtimer) { + printf("%s():l%u\n", __FILE__, __LINE__); + } + + memset(js_xtimer, '\0', sizeof(*js_xtimer)); + js_xtimer->callback.event.callback = js_event_callback; + js_xtimer->callback.callback = jerry_acquire_value(callback); + js_xtimer->callback.object = jerry_acquire_value(object); + js_xtimer->xtimer.callback = js_callback; + js_xtimer->xtimer.arg = js_xtimer; + xtimer_set(&js_xtimer->xtimer, timeout); + + return object; +} + +static JS_EXTERNAL_HANDLER(timer_setCallback) { + (void)func_value; + (void)this_value; + + if (args_cnt < 2) { + puts("timer.setCallback(): not enough arguments"); + return 0; + } + + if (!jerry_value_is_function(args_p[0])) { + puts("timer.setCallback(): arg 0 not a function"); + return 0; + } + if (!jerry_value_is_number(args_p[1])) { + puts("timer.setCallback(): arg 1 not a number"); + return 0; + } + + return js_xtimer_create(args_p[0], jerry_get_number_value(args_p[1])); +} + +static JS_EXTERNAL_HANDLER(timer_now) { + (void)func_value; + (void)this_value; + (void)args_p; + (void)args_cnt; + + return jerry_create_number(xtimer_now_usec()); +} + +const js_native_method_t timer_methods[] = { + { "setCallback", js_external_handler_timer_setCallback }, + { "now", js_external_handler_timer_now } +}; + +const unsigned timer_methods_len = sizeof(timer_methods) / sizeof(timer_methods[0]); From 4fa2be0fd64c1bff53c9a9b27aaa7caa2c0f1ba1 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 1 Sep 2017 08:44:40 +0200 Subject: [PATCH 02/17] examples/javascript: make use of js module --- examples/javascript/Makefile | 3 +-- examples/javascript/main.c | 46 +++++++++--------------------------- examples/javascript/main.js | 17 ++++++++++++- 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/examples/javascript/Makefile b/examples/javascript/Makefile index aaaa10be340a..c2f35f634561 100644 --- a/examples/javascript/Makefile +++ b/examples/javascript/Makefile @@ -24,8 +24,7 @@ CFLAGS += -DDEVELHELP # Set stack size to something (conservatively) enormous CFLAGS += -DTHREAD_STACKSIZE_MAIN=9092 -# Add the package for Jerryscript -USEPKG += jerryscript +USEMODULE += js include $(CURDIR)/../../Makefile.include diff --git a/examples/javascript/main.c b/examples/javascript/main.c index 18d7523c9ff9..9e9815cc5721 100644 --- a/examples/javascript/main.c +++ b/examples/javascript/main.c @@ -23,53 +23,29 @@ #include #include -#include "jerryscript.h" -#include "jerryscript-ext/handler.h" +#include "js.h" /* include header generated from main.js */ #include "main.js.h" -int js_run(const jerry_char_t *script, size_t script_size) -{ - jerry_value_t ret_value; - - /* Initialize engine */ - jerry_init(JERRY_INIT_EMPTY); - - /* Register the print function in the global object. */ - jerryx_handler_register_global((const jerry_char_t *) "print", jerryx_handler_print); - - /* Setup Global scope code */ - ret_value = jerry_parse(script, script_size, false); - - if (!jerry_value_has_error_flag(ret_value)) { - /* Execute the parsed source code in the Global scope */ - ret_value = jerry_run(ret_value); - } - - int res = 0; - - if (jerry_value_has_error_flag(ret_value)) { - printf("js_run(): Script Error!"); - res = -1; - } - - jerry_release_value(ret_value); - - /* Cleanup engine */ - jerry_cleanup(); - - return res; -} +static event_queue_t event_queue; int main(void) { printf("You are running RIOT on a(n) %s board.\n", RIOT_BOARD); printf("This board features a(n) %s MCU.\n", RIOT_MCU); - printf("Executing main.js:\n"); + event_queue_init(&event_queue); + + puts("Initializing jerryscript..."); + js_event_queue = &event_queue; + js_init(); + puts("Executing main.js..."); js_run(main_js, main_js_len); + puts("Entering event loop..."); + event_loop(&event_queue); + return 0; } diff --git a/examples/javascript/main.js b/examples/javascript/main.js index 0243cda17745..027053bbe14b 100644 --- a/examples/javascript/main.js +++ b/examples/javascript/main.js @@ -1 +1,16 @@ -print("Hello from JerryScript!"); +print("Hello from JerryScript!!!!"); + +timer.setInterval = function (callback, interval) { + var next = timer.now() + interval; + var interval_handler = function () { + callback(); + next += interval; + next_interval = next - timer.now(); + timer.setCallback(interval_handler, next_interval); + } + + return timer.setCallback(interval_handler, interval); +} + +var n = 0; +timer.setInterval(function () { n += 1; print(n, "triggers, time is", timer.now()); }, 1000000) From a40951029706501c4f590a98d99c6c1909102f9f Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 7 Sep 2017 13:03:21 +0200 Subject: [PATCH 03/17] sys/js: rename timer.setCallback() -> timer.setTimeout() --- examples/javascript/main.js | 4 ++-- sys/js/timer.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/javascript/main.js b/examples/javascript/main.js index 027053bbe14b..b9f2b2f2ea40 100644 --- a/examples/javascript/main.js +++ b/examples/javascript/main.js @@ -6,10 +6,10 @@ timer.setInterval = function (callback, interval) { callback(); next += interval; next_interval = next - timer.now(); - timer.setCallback(interval_handler, next_interval); + timer.setTimeout(interval_handler, next_interval); } - return timer.setCallback(interval_handler, interval); + return timer.setTimeout(interval_handler, interval); } var n = 0; diff --git a/sys/js/timer.c b/sys/js/timer.c index 81f0d0387eae..7333c1f4343f 100644 --- a/sys/js/timer.c +++ b/sys/js/timer.c @@ -48,21 +48,21 @@ static jerry_value_t js_xtimer_create(jerry_value_t callback, uint32_t timeout) return object; } -static JS_EXTERNAL_HANDLER(timer_setCallback) { +static JS_EXTERNAL_HANDLER(timer_setTimeout) { (void)func_value; (void)this_value; if (args_cnt < 2) { - puts("timer.setCallback(): not enough arguments"); + puts("timer.setTimeout(): not enough arguments"); return 0; } if (!jerry_value_is_function(args_p[0])) { - puts("timer.setCallback(): arg 0 not a function"); + puts("timer.setTimeout(): arg 0 not a function"); return 0; } if (!jerry_value_is_number(args_p[1])) { - puts("timer.setCallback(): arg 1 not a number"); + puts("timer.setTimeout(): arg 1 not a number"); return 0; } @@ -79,7 +79,7 @@ static JS_EXTERNAL_HANDLER(timer_now) { } const js_native_method_t timer_methods[] = { - { "setCallback", js_external_handler_timer_setCallback }, + { "setTimeout", js_external_handler_timer_setTimeout }, { "now", js_external_handler_timer_now } }; From 001938effcd4ad29d247108cf12cb0db2ee6d62b Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 7 Sep 2017 15:41:27 +0200 Subject: [PATCH 04/17] sys/js: add initial saul support --- Makefile.dep | 2 + sys/js/init.c | 11 ++++- sys/js/js.c | 11 +++-- sys/js/saul.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 sys/js/saul.c diff --git a/Makefile.dep b/Makefile.dep index b9604b07317e..b283efb26bb3 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -719,6 +719,8 @@ ifneq (,$(filter js,$(USEMODULE))) USEPKG += jerryscript USEMODULE += xtimer USEMODULE += event + USEMODULE += saul_reg + USEMODULE += saul_default endif # always select gpio (until explicit dependencies are sorted out) diff --git a/sys/js/init.c b/sys/js/init.c index 1ae151c21826..f4227fa816e5 100644 --- a/sys/js/init.c +++ b/sys/js/init.c @@ -1,11 +1,14 @@ #include "event.h" #include "js.h" +extern const js_native_method_t riot_methods[]; +extern const unsigned riot_methods_len; + extern const js_native_method_t timer_methods[]; extern const unsigned timer_methods_len; -extern const js_native_method_t riot_methods[]; -extern const unsigned riot_methods_len; +extern const js_native_method_t saul_methods[]; +extern const unsigned saul_methods_len; void js_init_objects(void) { @@ -19,5 +22,9 @@ void js_init_objects(void) js_add_object(global_object, timer_object, "timer"); jerry_release_value(timer_object); + jerry_value_t saul_object = js_object_create_with_methods(saul_methods, saul_methods_len); + js_add_object(global_object, saul_object, "saul"); + jerry_release_value(saul_object); + jerry_release_value(global_object); } diff --git a/sys/js/js.c b/sys/js/js.c index 1011f18eaa4e..902b3d186071 100644 --- a/sys/js/js.c +++ b/sys/js/js.c @@ -33,12 +33,15 @@ void js_add_object(jerry_value_t object, jerry_value_t other, const char *name) jerry_value_t js_object_native_create(size_t size, const jerry_object_native_info_t *native_obj_type_info) { jerry_value_t object = jerry_create_object(); - void *native_obj = malloc(size); - if (!native_obj) { - printf("%s(): malloc failed\n", __func__); + if (size) { + void *native_obj = malloc(size); + if (!native_obj) { + printf("%s(): malloc failed\n", __func__); + } + jerry_set_object_native_pointer(object, native_obj, native_obj_type_info); } - jerry_set_object_native_pointer(object, native_obj, native_obj_type_info); + return object; } diff --git a/sys/js/saul.c b/sys/js/saul.c new file mode 100644 index 000000000000..6dc57cf3304e --- /dev/null +++ b/sys/js/saul.c @@ -0,0 +1,129 @@ +#include +#include +#include + +#include "event.h" +#include "js.h" +#include "saul_reg.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static void _js_saul_reg_freecb(void *native_p) +{ + (void)native_p; + DEBUG("%s:l%u:%s()\n", __FILE__, __LINE__, __func__); +} + +static const jerry_object_native_info_t js_saul_reg_object_native_info = +{ + .free_cb = _js_saul_reg_freecb +}; + +static JS_EXTERNAL_HANDLER(saul_reg_read) +{ + (void)func_value; +// (void)this_value; + (void)args_p; + (void)args_cnt; + + phydat_t phydat; + saul_reg_t *saul_reg = js_get_object_native_pointer(this_value, &js_saul_reg_object_native_info); + if (!saul_reg) { + puts("nosaulreg"); + goto error; + } + int res = saul_reg_read(saul_reg, &phydat); + if (res < 1) { + puts("saulnothingread"); + goto error; + } + return jerry_create_number(phydat.val[0]); + +error: + return jerry_create_undefined(); +} + +static JS_EXTERNAL_HANDLER(saul_reg_write) +{ + (void)func_value; +// (void)this_value; + (void)args_p; + (void)args_cnt; + + saul_reg_t *saul_reg = js_get_object_native_pointer(this_value, &js_saul_reg_object_native_info); + if (!saul_reg) { + puts("nosaulreg"); + goto error; + } + if (args_cnt < 1) { + puts("saul_write(): not enough arguments"); + goto error; + } + + phydat_t phydat; + memset(&phydat, '\0', sizeof(phydat)); + + for (unsigned i = 0; i < args_cnt; i++) { + if (jerry_value_is_number(args_p[i])) { + phydat.val[i] = jerry_get_number_value(args_p[i]); + } else { + printf("saul_write(): arg %i is not a number!", i); + goto error; + } + } + + saul_reg_write(saul_reg, &phydat); + +error: + return jerry_create_undefined(); +} + +const js_native_method_t saul_reg_methods[] = { + { "read", js_external_handler_saul_reg_read }, + { "write", js_external_handler_saul_reg_write }, +}; + +const unsigned saul_reg_methods_len = sizeof(saul_reg_methods) / sizeof(saul_reg_methods[0]); + +static jerry_value_t js_saul_reg_create(saul_reg_t *saul_reg) +{ + jerry_value_t object = js_object_create_with_methods(saul_reg_methods, saul_reg_methods_len); + jerry_set_object_native_pointer(object, saul_reg, &js_saul_reg_object_native_info); + return object; +} + +static JS_EXTERNAL_HANDLER(saul_get_one) { + (void)func_value; + (void)this_value; + + if (args_cnt < 1) { + puts("saul.get_one(): not enough arguments"); + return 0; + } + + if (!jerry_value_is_number(args_p[0])) { + puts("saul.get_one(): arg 0 not a saul type"); + return 0; + } + +/* int pos = 0; + if ((args_cnt) > 1 && jerry_value_is_number(args_p[1])) { + pos = jerry_get_number_value(args_p[1]); + } +*/ + + saul_reg_t *entry = saul_reg_find_type(jerry_get_number_value(args_p[0])); + if (entry) { + return js_saul_reg_create(entry); + } else { + return jerry_create_undefined(); + } +} + +const js_native_method_t saul_methods[] = { + { "_get_one", js_external_handler_saul_get_one }, +// { "get_by_name", js_external_handler_saul_get_by_name } +}; + +const unsigned saul_methods_len = sizeof(saul_methods) / sizeof(saul_methods[0]); From 8e361ef91e1d8684b166eb5f1e07b85c1fe2be09 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 7 Sep 2017 15:42:41 +0200 Subject: [PATCH 05/17] examples/javascript: split js into lib.js and main.js --- examples/javascript/lib.js | 85 +++++++++++++++++++++++++++++++++++++ examples/javascript/main.c | 6 ++- examples/javascript/main.js | 20 ++++----- 3 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 examples/javascript/lib.js diff --git a/examples/javascript/lib.js b/examples/javascript/lib.js new file mode 100644 index 000000000000..8297cfde8ed5 --- /dev/null +++ b/examples/javascript/lib.js @@ -0,0 +1,85 @@ +print("Hello from lib.js"); + +timer.setInterval = function (callback, interval) { + var next = timer.now() + interval; + var interval_handler = function () { + var res = callback(); + if (res == true) { + next += interval; + next_interval = next - timer.now(); + timer.setTimeout(interval_handler, next_interval); + } + } + + return timer.setTimeout(interval_handler, interval); +} + +saul.type = { + CLASS_UNDEF : 0x00, /**< device class undefined */ + ACT_ANY : 0x40, /**< any actuator - wildcard */ + ACT_LED_RGB : 0x42, /**< actuator: RGB LED */ + ACT_SERVO : 0x43, /**< actuator: servo motor */ + ACT_MOTOR : 0x44, /**< actuator: motor */ + ACT_SWITCH : 0x45, /**< actuator: simple on/off switch */ + ACT_DIMMER : 0x46, /**< actuator: dimmable switch */ + SENSE_ANY : 0x80, /**< any sensor - wildcard */ + SENSE_BTN : 0x81, /**< sensor: simple button */ + SENSE_TEMP : 0x82, /**< sensor: temperature */ + SENSE_HUM : 0x83, /**< sensor: humidity */ + SENSE_LIGHT : 0x84, /**< sensor: light */ + SENSE_ACCEL : 0x85, /**< sensor: accelerometer */ + SENSE_MAG : 0x86, /**< sensor: magnetometer */ + SENSE_GYRO : 0x87, /**< sensor: gyroscope */ + SENSE_COLOR : 0x88, /**< sensor: (light) color */ + SENSE_PRESS : 0x89, /**< sensor: pressure */ + SENSE_ANALOG : 0x8a, /**< sensor: raw analog value */ + SENSE_UV : 0x8b, /**< sensor: UV index */ + CLASS_ANY : 0xff /**< any device - wildcard */ +} + +saul.op = { + LT : 0, + LE : 1, + EQ : 2, + GE : 3, + GT : 4 +} + +saul.get_one = function(type) { + var res = saul._get_one(type); + if (typeof type !== 'undefined') { + res.on_threshold = function(threshold, callback, operator) { + var sensor = this; + var operator = (typeof operator !== 'undefined') ? operator : saul.op.GE; + var poller = function() { + var val = sensor.read(); + var trigger = false; + switch (operator) { + case saul.op.LT: + trigger = (val < threshold); + break; + case saul.op.LE: + trigger = (val <= threshold); + break; + case saul.op.EQ: + trigger = (val == threshold); + break; + case saul.op.GE: + trigger = (val >= threshold); + break; + case saul.op.GT: + trigger = (val > threshold); + break; + } + if (trigger) { + return callback(); + } else { + return true; + } + } + + return timer.setInterval(poller, 100000); + } + } + return res; +} diff --git a/examples/javascript/main.c b/examples/javascript/main.c index 9e9815cc5721..4d463d9fc0e7 100644 --- a/examples/javascript/main.c +++ b/examples/javascript/main.c @@ -25,7 +25,8 @@ #include "js.h" -/* include header generated from main.js */ +/* include headers generated from *.js */ +#include "lib.js.h" #include "main.js.h" static event_queue_t event_queue; @@ -41,6 +42,9 @@ int main(void) js_event_queue = &event_queue; js_init(); + puts("Executing lib.js..."); + js_run(lib_js, lib_js_len); + puts("Executing main.js..."); js_run(main_js, main_js_len); diff --git a/examples/javascript/main.js b/examples/javascript/main.js index b9f2b2f2ea40..9dd236f356e8 100644 --- a/examples/javascript/main.js +++ b/examples/javascript/main.js @@ -1,16 +1,12 @@ print("Hello from JerryScript!!!!"); -timer.setInterval = function (callback, interval) { - var next = timer.now() + interval; - var interval_handler = function () { - callback(); - next += interval; - next_interval = next - timer.now(); - timer.setTimeout(interval_handler, next_interval); - } +//var n = 0; +//timer.setInterval(function () { n += 1; print(n, "triggers, time is", timer.now()); }, 1000000); - return timer.setTimeout(interval_handler, interval); -} +button = saul.get_one(saul.type.SENSE_BTN); +led = saul.get_one(saul.type.ACT_SWITCH); -var n = 0; -timer.setInterval(function () { n += 1; print(n, "triggers, time is", timer.now()); }, 1000000) +led.write(1); + +button.on_threshold(0, function(){led.write(0); return true;}, saul.op.EQ); +button.on_threshold(1, function(){led.write(1); return true;}); From 456bd0ca2bf66925fc2c79a3fb574f55b86521aa Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Tue, 12 Sep 2017 11:58:03 +0200 Subject: [PATCH 06/17] lib.js: add saul.sample() --- examples/javascript/lib.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/examples/javascript/lib.js b/examples/javascript/lib.js index 8297cfde8ed5..418aef1c2168 100644 --- a/examples/javascript/lib.js +++ b/examples/javascript/lib.js @@ -80,6 +80,24 @@ saul.get_one = function(type) { return timer.setInterval(poller, 100000); } + res.sample = function(n) { + var result = { + min : Number.MAX_VALUE, + max : Number.MIN_VALUE, + avg : 0 + } + + var left = n + while (left > 0) { + var val = this.read(); + result.avg += val; + result.max = Math.max(result.max, val); + result.min = Math.min(result.min, val); + left -= 1; + } + result.avg /= n; + return result; + } } return res; } From 8894ecc7eef5db4f8e5e2acb9308dd8b29243dd8 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 13 Sep 2017 12:02:01 +0200 Subject: [PATCH 07/17] sys/js: keep list of native referecences to js objects --- sys/include/js.h | 13 +++++++++++-- sys/js/js.c | 38 ++++++++++++++++++++++++++++++++++++-- sys/js/timer.c | 12 +++++++++--- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/sys/include/js.h b/sys/include/js.h index 74c0b3b721e7..f30c1bbe54fe 100644 --- a/sys/include/js.h +++ b/sys/include/js.h @@ -1,6 +1,7 @@ #ifndef JS_H #define JS_H +#include "clist.h" #include "event.h" #include "jerryscript.h" #include "jerryscript-ext/handler.h" @@ -18,11 +19,17 @@ typedef struct { } js_native_objects_t; typedef struct { - event_t event; - jerry_value_t callback; + list_node_t ref; jerry_value_t object; +} js_native_ref_t; + +typedef struct { + event_t event; + js_native_ref_t callback; } js_callback_t; +extern list_node_t js_native_refs; + void js_init(event_queue_t *queue); int js_run(const jerry_char_t *script, size_t script_size); @@ -35,6 +42,8 @@ jerry_value_t js_object_native_create(size_t size, const jerry_object_native_inf void js_callback(void *arg); void js_event_callback(event_t *event); void js_run_callback(jerry_value_t callback); +void js_callback_cancel(js_callback_t *callback); +void js_shutdown(void); #define JS_EXTERNAL_HANDLER(name) \ jerry_value_t \ diff --git a/sys/js/js.c b/sys/js/js.c index 902b3d186071..16713e8a166b 100644 --- a/sys/js/js.c +++ b/sys/js/js.c @@ -8,6 +8,7 @@ #include "debug.h" event_queue_t *js_event_queue; +list_node_t js_native_refs; void js_add_external_handler(jerry_value_t object, const char *name, jerry_external_handler_t handler) { @@ -98,8 +99,13 @@ void js_callback(void *arg) void js_event_callback(event_t *event) { js_callback_t *js_callback = (js_callback_t *) event; - js_run_callback(js_callback->callback); - jerry_release_value(js_callback->object); + js_run_callback(js_callback->callback.object); + clist_remove(&js_native_refs, &js_callback->callback.ref); +} + +void js_callback_cancel(js_callback_t *callback) +{ + event_cancel(js_event_queue, &callback->event); } int js_run(const jerry_char_t *script, size_t script_size) @@ -138,3 +144,31 @@ void js_init(event_queue_t *queue) js_init_objects(); } + +static void js_shutdown_event_handler(event_t *event) +{ + (void)event; + + unsigned state = irq_disable(); + + /* drain all events from queue */ + while (event_get(js_event_queue)); + + /* un-reference all jerryscript objects referenced by native code */ + js_native_ref_t *ref; + while ((ref = (js_native_ref_t*) clist_lpop(&js_native_refs))) { + jerry_release_value(ref->object); + } + + /* cleanup jerryscript engine */ + jerry_cleanup(); + + irq_restore(state); +} + +static event_t js_shutdown_event = { .handler = js_shutdown_event_handler }; + +void js_shutdown(void) +{ + event_post(js_event_queue, &js_shutdown_event); +} diff --git a/sys/js/timer.c b/sys/js/timer.c index 7333c1f4343f..d1d07cabbd0d 100644 --- a/sys/js/timer.c +++ b/sys/js/timer.c @@ -19,7 +19,9 @@ static void _js_xtimer_freecb(void *native_p) DEBUG("%s:l%u:%s()\n", __FILE__, __LINE__, __func__); js_xtimer_t *js_xtimer = (js_xtimer_t *) native_p; + clist_remove(&js_native_refs, &js_xtimer->callback.callback.ref); xtimer_remove(&js_xtimer->xtimer); + js_callback_cancel(&js_xtimer->callback); free(js_xtimer); } @@ -34,13 +36,17 @@ static jerry_value_t js_xtimer_create(jerry_value_t callback, uint32_t timeout) js_xtimer_t *js_xtimer = js_get_object_native_pointer(object, &js_xtimer_object_native_info); if (!js_xtimer) { - printf("%s():l%u\n", __FILE__, __LINE__); + DEBUG("%s():l%u\n", __FILE__, __LINE__); } + /* add the xtimer object as property to the callback so + * it stays referenced */ + js_add_object(callback, object, "_obj"); + memset(js_xtimer, '\0', sizeof(*js_xtimer)); js_xtimer->callback.event.callback = js_event_callback; - js_xtimer->callback.callback = jerry_acquire_value(callback); - js_xtimer->callback.object = jerry_acquire_value(object); + js_xtimer->callback.callback.object = jerry_acquire_value(callback); + clist_rpush(&js_native_refs, &js_xtimer->callback.callback.ref); js_xtimer->xtimer.callback = js_callback; js_xtimer->xtimer.arg = js_xtimer; xtimer_set(&js_xtimer->xtimer, timeout); From 8f2eaf56c707b2b8c592f481ea05766eadf10797 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 13 Sep 2017 16:32:24 +0200 Subject: [PATCH 08/17] sys/js: refactor callback handling --- sys/include/js.h | 7 ++++--- sys/js/callback.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ sys/js/js.c | 27 ++++--------------------- sys/js/timer.c | 9 +++------ 4 files changed, 62 insertions(+), 32 deletions(-) create mode 100644 sys/js/callback.c diff --git a/sys/include/js.h b/sys/include/js.h index f30c1bbe54fe..af53462ea68f 100644 --- a/sys/include/js.h +++ b/sys/include/js.h @@ -39,9 +39,10 @@ void js_add_object(jerry_value_t object, jerry_value_t other, const char *name); void *js_get_object_native_pointer(jerry_value_t object, const jerry_object_native_info_t *type); jerry_value_t js_object_create_with_methods(const js_native_method_t *methods, unsigned num_methods); jerry_value_t js_object_native_create(size_t size, const jerry_object_native_info_t *native_obj_type_info); -void js_callback(void *arg); -void js_event_callback(event_t *event); -void js_run_callback(jerry_value_t callback); +void js_callback_isr(void *arg); +void js_call_function(jerry_value_t callback); +void js_callback_init(js_callback_t *js_callback, jerry_value_t callback); +void js_callback_run(js_callback_t *js_callback); void js_callback_cancel(js_callback_t *callback); void js_shutdown(void); diff --git a/sys/js/callback.c b/sys/js/callback.c new file mode 100644 index 000000000000..a9cf47665725 --- /dev/null +++ b/sys/js/callback.c @@ -0,0 +1,51 @@ +#include "js.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +void js_callback_isr(void *arg) +{ + js_callback_t *js_callback = (js_callback_t *)arg; + DEBUG("trigger %p\n", js_callback); + event_post(js_event_queue, &js_callback->event); +} + +static void js_event_callback(event_t *event) +{ + js_callback_t *js_callback = (js_callback_t *) event; + js_callback_run(js_callback); +} + +void js_callback_init(js_callback_t *js_callback, jerry_value_t callback) +{ + DEBUG("init %p\n", js_callback); + js_callback->event.callback = js_event_callback; + js_callback->callback.object = jerry_acquire_value(callback); + DEBUG("acquire obj %lu\n", js_callback->callback.object); + clist_rpush(&js_native_refs, &js_callback->callback.ref); +} + +static void js_callback_cleanup(js_callback_t *js_callback) +{ + DEBUG("cleanup %p\n", js_callback); + jerry_value_t callback = js_callback->callback.object; + jerry_release_value(callback); + clist_remove(&js_native_refs, &js_callback->callback.ref); + DEBUG("release %lu\n", callback); +} + +void js_callback_run(js_callback_t *js_callback) +{ + DEBUG("run %p\n", js_callback); + jerry_value_t callback = js_callback->callback.object; + js_call_function(callback); + js_callback_cleanup(js_callback); +} + +void js_callback_cancel(js_callback_t *js_callback) +{ + DEBUG("cancel %p\n", js_callback); + event_cancel(js_event_queue, &js_callback->event); + js_callback_cleanup(js_callback); +} + diff --git a/sys/js/js.c b/sys/js/js.c index 16713e8a166b..a335063328b7 100644 --- a/sys/js/js.c +++ b/sys/js/js.c @@ -68,11 +68,11 @@ jerry_value_t js_object_create_with_methods(const js_native_method_t *methods, u return object; } -void js_run_callback(jerry_value_t callback) +void js_call_function(jerry_value_t function) { - if (jerry_value_is_function(callback)) { + if (jerry_value_is_function(function)) { jerry_value_t this_val = jerry_create_undefined(); - jerry_value_t ret_val = jerry_call_function(callback, this_val, NULL, 0); + jerry_value_t ret_val = jerry_call_function(function, this_val, NULL, 0); if (!jerry_value_has_error_flag(ret_val)) { DEBUG("%s():l%u %s\n", __FILE__, __LINE__, __func__); @@ -87,25 +87,6 @@ void js_run_callback(jerry_value_t callback) else { printf("%s():l%u %s\n", __FILE__, __LINE__, __func__); } - jerry_release_value(callback); -} - -void js_callback(void *arg) -{ - js_callback_t *js_callback = (js_callback_t *)arg; - event_post(js_event_queue, &js_callback->event); -} - -void js_event_callback(event_t *event) -{ - js_callback_t *js_callback = (js_callback_t *) event; - js_run_callback(js_callback->callback.object); - clist_remove(&js_native_refs, &js_callback->callback.ref); -} - -void js_callback_cancel(js_callback_t *callback) -{ - event_cancel(js_event_queue, &callback->event); } int js_run(const jerry_char_t *script, size_t script_size) @@ -151,7 +132,7 @@ static void js_shutdown_event_handler(event_t *event) unsigned state = irq_disable(); - /* drain all events from queue */ + /* drain all js callbackevents from queue */ while (event_get(js_event_queue)); /* un-reference all jerryscript objects referenced by native code */ diff --git a/sys/js/timer.c b/sys/js/timer.c index d1d07cabbd0d..cf116c5dea16 100644 --- a/sys/js/timer.c +++ b/sys/js/timer.c @@ -11,6 +11,7 @@ typedef struct { js_callback_t callback; + jerry_value_t object; xtimer_t xtimer; } js_xtimer_t; @@ -19,9 +20,7 @@ static void _js_xtimer_freecb(void *native_p) DEBUG("%s:l%u:%s()\n", __FILE__, __LINE__, __func__); js_xtimer_t *js_xtimer = (js_xtimer_t *) native_p; - clist_remove(&js_native_refs, &js_xtimer->callback.callback.ref); xtimer_remove(&js_xtimer->xtimer); - js_callback_cancel(&js_xtimer->callback); free(js_xtimer); } @@ -44,10 +43,8 @@ static jerry_value_t js_xtimer_create(jerry_value_t callback, uint32_t timeout) js_add_object(callback, object, "_obj"); memset(js_xtimer, '\0', sizeof(*js_xtimer)); - js_xtimer->callback.event.callback = js_event_callback; - js_xtimer->callback.callback.object = jerry_acquire_value(callback); - clist_rpush(&js_native_refs, &js_xtimer->callback.callback.ref); - js_xtimer->xtimer.callback = js_callback; + js_callback_init(&js_xtimer->callback, callback); + js_xtimer->xtimer.callback = js_callback_isr; js_xtimer->xtimer.arg = js_xtimer; xtimer_set(&js_xtimer->xtimer, timeout); From 04c1d550b4e90a60ddbf6e67943fa8b0cc2d41a7 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 13 Sep 2017 17:20:02 +0200 Subject: [PATCH 09/17] sys/js: add saul.get_by_name() support --- examples/javascript/lib.js | 14 +++++++++----- sys/js/saul.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/examples/javascript/lib.js b/examples/javascript/lib.js index 418aef1c2168..fe51afe16a55 100644 --- a/examples/javascript/lib.js +++ b/examples/javascript/lib.js @@ -45,10 +45,9 @@ saul.op = { GT : 4 } -saul.get_one = function(type) { - var res = saul._get_one(type); - if (typeof type !== 'undefined') { - res.on_threshold = function(threshold, callback, operator) { +saul.set_methods = function(saul_object) { + if (typeof saul_object !== 'undefined') { + saul_object.on_threshold = function(threshold, callback, operator) { var sensor = this; var operator = (typeof operator !== 'undefined') ? operator : saul.op.GE; var poller = function() { @@ -80,7 +79,7 @@ saul.get_one = function(type) { return timer.setInterval(poller, 100000); } - res.sample = function(n) { + saul_object.sample = function(n) { var result = { min : Number.MAX_VALUE, max : Number.MIN_VALUE, @@ -99,5 +98,10 @@ saul.get_one = function(type) { return result; } } +} + +saul.get_one = function(type) { + var res = saul._get_one(type); + saul.set_methods(res); return res; } diff --git a/sys/js/saul.c b/sys/js/saul.c index 6dc57cf3304e..0d4945f09253 100644 --- a/sys/js/saul.c +++ b/sys/js/saul.c @@ -6,7 +6,7 @@ #include "js.h" #include "saul_reg.h" -#define ENABLE_DEBUG (0) +#define ENABLE_DEBUG (1) #include "debug.h" static void _js_saul_reg_freecb(void *native_p) @@ -121,9 +121,35 @@ static JS_EXTERNAL_HANDLER(saul_get_one) { } } +static JS_EXTERNAL_HANDLER(saul_find_name) { + (void)func_value; + (void)this_value; + + if (args_cnt < 1) { + puts("saul.get_by_name(): not enough arguments"); + return 0; + } + + if (!jerry_value_is_string(args_p[0])) { + puts("saul.get_by_name(): arg 0 not a string"); + return 0; + } + + char name[32]; + memset(name, '\0', sizeof(name)); + jerry_string_to_char_buffer(args_p[0], (jerry_char_t*)name, sizeof(name)); + saul_reg_t *entry = saul_reg_find_name(name); + if (entry) { + DEBUG("saul_find_name(): found entry for name \"%s\"\n", name); + return js_saul_reg_create(entry); + } else { + DEBUG("saul_find_name(): no entry found for name \"%s\"\n", name); + return jerry_create_undefined(); + } +} const js_native_method_t saul_methods[] = { { "_get_one", js_external_handler_saul_get_one }, -// { "get_by_name", js_external_handler_saul_get_by_name } + { "_find_name", js_external_handler_saul_find_name } }; const unsigned saul_methods_len = sizeof(saul_methods) / sizeof(saul_methods[0]); From 2e03d160755a0800e55082f3e947ae40b5edd367 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 14 Sep 2017 10:45:59 +0200 Subject: [PATCH 10/17] sys/js: lib.js: change setInterval() abort condindition to "!=false" --- examples/javascript/lib.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/javascript/lib.js b/examples/javascript/lib.js index fe51afe16a55..6ba0e2a59a21 100644 --- a/examples/javascript/lib.js +++ b/examples/javascript/lib.js @@ -4,9 +4,12 @@ timer.setInterval = function (callback, interval) { var next = timer.now() + interval; var interval_handler = function () { var res = callback(); - if (res == true) { - next += interval; - next_interval = next - timer.now(); + if (res != false) { + now = timer.now(); + while (next < now) { + next += interval; + } + next_interval = next - now; timer.setTimeout(interval_handler, next_interval); } } From 92895fa618dcc46eed1a9a8decee76466b974b9a Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 14 Sep 2017 14:08:17 +0200 Subject: [PATCH 11/17] sys/js: lib.js: change on_threshold to event semantics --- examples/javascript/lib.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/javascript/lib.js b/examples/javascript/lib.js index 6ba0e2a59a21..d8ba7f0b2f2d 100644 --- a/examples/javascript/lib.js +++ b/examples/javascript/lib.js @@ -53,6 +53,8 @@ saul.set_methods = function(saul_object) { saul_object.on_threshold = function(threshold, callback, operator) { var sensor = this; var operator = (typeof operator !== 'undefined') ? operator : saul.op.GE; + var wait_flank = true; + var poller = function() { var val = sensor.read(); var trigger = false; @@ -73,9 +75,14 @@ saul.set_methods = function(saul_object) { trigger = (val > threshold); break; } - if (trigger) { + + if (trigger && wait_flank) { + wait_flank = false; return callback(); } else { + if (! (trigger || wait_flank)) { + wait_flank = true; + } return true; } } From 1abe9a5e63709d72cb4aac9deec0e70b9f2c3258 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 20 Sep 2017 14:15:04 +0200 Subject: [PATCH 12/17] sys/js: optionally execute event after js_shutdown() --- sys/include/js.h | 2 +- sys/js/js.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sys/include/js.h b/sys/include/js.h index af53462ea68f..853f338dc810 100644 --- a/sys/include/js.h +++ b/sys/include/js.h @@ -44,7 +44,7 @@ void js_call_function(jerry_value_t callback); void js_callback_init(js_callback_t *js_callback, jerry_value_t callback); void js_callback_run(js_callback_t *js_callback); void js_callback_cancel(js_callback_t *callback); -void js_shutdown(void); +void js_shutdown(event_t *shutdown_done_event); #define JS_EXTERNAL_HANDLER(name) \ jerry_value_t \ diff --git a/sys/js/js.c b/sys/js/js.c index a335063328b7..d55720eeb094 100644 --- a/sys/js/js.c +++ b/sys/js/js.c @@ -126,6 +126,8 @@ void js_init(event_queue_t *queue) js_init_objects(); } +static event_t *js_shutdown_done_event; + static void js_shutdown_event_handler(event_t *event) { (void)event; @@ -145,11 +147,16 @@ static void js_shutdown_event_handler(event_t *event) jerry_cleanup(); irq_restore(state); + + if (js_shutdown_done_event) { + event_post(js_event_queue, js_shutdown_done_event); + } } static event_t js_shutdown_event = { .handler = js_shutdown_event_handler }; -void js_shutdown(void) +void js_shutdown(event_t *done_event) { + js_shutdown_done_event = done_event; event_post(js_event_queue, &js_shutdown_event); } From 6c693d626232d30c4255fcfc4e88160d8ef20ee2 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Wed, 20 Sep 2017 14:27:34 +0200 Subject: [PATCH 13/17] sys/js: don't set js_event_queue in js_init() --- sys/include/js.h | 2 +- sys/js/js.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/include/js.h b/sys/include/js.h index 853f338dc810..42d590b4d3f9 100644 --- a/sys/include/js.h +++ b/sys/include/js.h @@ -30,7 +30,7 @@ typedef struct { extern list_node_t js_native_refs; -void js_init(event_queue_t *queue); +void js_init(void); int js_run(const jerry_char_t *script, size_t script_size); /* internal */ diff --git a/sys/js/js.c b/sys/js/js.c index d55720eeb094..f2a58b8206cc 100644 --- a/sys/js/js.c +++ b/sys/js/js.c @@ -113,9 +113,9 @@ int js_run(const jerry_char_t *script, size_t script_size) return res; } -void js_init(event_queue_t *queue) +void js_init(void) { - js_event_queue = queue; + assert(js_event_queue); /* Initialize engine */ jerry_init(JERRY_INIT_EMPTY); From 0ce89f1473280db4028dca8bbceb21d7fd375b10 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 19 Oct 2017 15:20:37 +0200 Subject: [PATCH 14/17] sys/js: refactor native reference mechanics --- sys/include/js.h | 4 ++-- sys/js/callback.c | 9 +++------ sys/js/js.c | 16 +++++++++++++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/sys/include/js.h b/sys/include/js.h index 42d590b4d3f9..7d253fb57873 100644 --- a/sys/include/js.h +++ b/sys/include/js.h @@ -28,12 +28,12 @@ typedef struct { js_native_ref_t callback; } js_callback_t; -extern list_node_t js_native_refs; - void js_init(void); int js_run(const jerry_char_t *script, size_t script_size); /* internal */ +void js_native_ref_add(js_native_ref_t *ref, jerry_value_t object); +void js_native_ref_rem(js_native_ref_t *ref); void js_init_objects(void); void js_add_object(jerry_value_t object, jerry_value_t other, const char *name); void *js_get_object_native_pointer(jerry_value_t object, const jerry_object_native_info_t *type); diff --git a/sys/js/callback.c b/sys/js/callback.c index a9cf47665725..0075227e747b 100644 --- a/sys/js/callback.c +++ b/sys/js/callback.c @@ -20,18 +20,15 @@ void js_callback_init(js_callback_t *js_callback, jerry_value_t callback) { DEBUG("init %p\n", js_callback); js_callback->event.callback = js_event_callback; - js_callback->callback.object = jerry_acquire_value(callback); + DEBUG("acquire obj %lu\n", js_callback->callback.object); - clist_rpush(&js_native_refs, &js_callback->callback.ref); + js_native_ref_add(&js_callback->callback, callback); } static void js_callback_cleanup(js_callback_t *js_callback) { - DEBUG("cleanup %p\n", js_callback); - jerry_value_t callback = js_callback->callback.object; - jerry_release_value(callback); - clist_remove(&js_native_refs, &js_callback->callback.ref); DEBUG("release %lu\n", callback); + js_native_ref_rem(&js_callback->callback); } void js_callback_run(js_callback_t *js_callback) diff --git a/sys/js/js.c b/sys/js/js.c index f2a58b8206cc..be4e7056d751 100644 --- a/sys/js/js.c +++ b/sys/js/js.c @@ -8,7 +8,7 @@ #include "debug.h" event_queue_t *js_event_queue; -list_node_t js_native_refs; +static list_node_t js_native_refs; void js_add_external_handler(jerry_value_t object, const char *name, jerry_external_handler_t handler) { @@ -160,3 +160,17 @@ void js_shutdown(event_t *done_event) js_shutdown_done_event = done_event; event_post(js_event_queue, &js_shutdown_event); } + +void js_native_ref_add(js_native_ref_t *ref, jerry_value_t object) +{ + ref->object = jerry_acquire_value(object); + clist_rpush(&js_native_refs, &ref->ref); +} + +void js_native_ref_rem(js_native_ref_t *ref) +{ + /* TODO: unfortunately, this is O(n) */ + if (clist_remove(&js_native_refs, &ref->ref)) { + jerry_release_value(ref->object); + } +} From 639b17eecd1ed707c26a4be42f7146d4f6c3200d Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 19 Oct 2017 17:57:02 +0200 Subject: [PATCH 15/17] sys/js: add some helper functions --- sys/include/js.h | 6 ++++++ sys/js/js.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/sys/include/js.h b/sys/include/js.h index 7d253fb57873..206898886ba4 100644 --- a/sys/include/js.h +++ b/sys/include/js.h @@ -45,6 +45,12 @@ void js_callback_init(js_callback_t *js_callback, jerry_value_t callback); void js_callback_run(js_callback_t *js_callback); void js_callback_cancel(js_callback_t *callback); void js_shutdown(event_t *shutdown_done_event); +char *js_strdup(jerry_value_t string); + +double js_object_get_number(jerry_value_t object, const char *name); +jerry_value_t js_get_property(jerry_value_t object, const char *name); + +#define js_check(x) if (jerry_value_has_error_flag(x)) printf("%s:%u: js_check("#x") failed!\n", __FILE__, __LINE__) #define JS_EXTERNAL_HANDLER(name) \ jerry_value_t \ diff --git a/sys/js/js.c b/sys/js/js.c index be4e7056d751..c67271deb181 100644 --- a/sys/js/js.c +++ b/sys/js/js.c @@ -14,11 +14,16 @@ void js_add_external_handler(jerry_value_t object, const char *name, jerry_exter { /* Create a JS function object and wrap into a jerry value */ jerry_value_t func_obj = jerry_create_external_function(handler); + js_check(func_obj); /* Set the native function as a property of the empty JS object */ jerry_value_t prop_name = jerry_create_string((const jerry_char_t *) name); + js_check(prop_name); - jerry_release_value(jerry_set_property(object, prop_name, func_obj)); + jerry_value_t set_prop = jerry_set_property(object, prop_name, func_obj); + js_check(set_prop); + + jerry_release_value(set_prop); jerry_release_value(prop_name); jerry_release_value(func_obj); } @@ -26,11 +31,39 @@ void js_add_external_handler(jerry_value_t object, const char *name, jerry_exter void js_add_object(jerry_value_t object, jerry_value_t other, const char *name) { jerry_value_t prop_name = jerry_create_string((const jerry_char_t *) name); + js_check(prop_name); + + jerry_value_t set_prop = jerry_set_property(object, prop_name, other); + js_check(set_prop); - jerry_release_value(jerry_set_property(object, prop_name, other)); + jerry_release_value(set_prop); jerry_release_value(prop_name); } +jerry_value_t js_get_property(jerry_value_t object, const char *name) +{ + jerry_value_t prop_name = jerry_create_string ((const jerry_char_t *) name); + jerry_value_t prop_value = jerry_get_property (object, prop_name); + jerry_release_value (prop_name); + return prop_value; +} + +double js_object_get_number(jerry_value_t object, const char *name) +{ + double res; + jerry_value_t prop_value = js_get_property(object, name); + if (jerry_value_is_number(prop_value)) { + res = jerry_get_number_value(prop_value); + } + else { + res = 0; + } + + jerry_release_value(prop_value); + + return res; +} + jerry_value_t js_object_native_create(size_t size, const jerry_object_native_info_t *native_obj_type_info) { jerry_value_t object = jerry_create_object(); @@ -161,6 +194,20 @@ void js_shutdown(event_t *done_event) event_post(js_event_queue, &js_shutdown_event); } +char *js_strdup(jerry_value_t string) +{ + size_t len = jerry_get_string_length(string); + if (!len) { + return NULL; + } + + char *buf = malloc(len+1); + if (buf) { + buf[jerry_string_to_char_buffer(string, (uint8_t*)buf, len)] = '\0'; + } + return buf; +} + void js_native_ref_add(js_native_ref_t *ref, jerry_value_t object) { ref->object = jerry_acquire_value(object); From ecb753a0ffac8a455c0ef2ce545a814d5e13a202 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Mon, 23 Oct 2017 17:21:57 +0200 Subject: [PATCH 16/17] sys/js/callback: fix rebase error --- sys/js/callback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/js/callback.c b/sys/js/callback.c index 0075227e747b..765c4354b6b5 100644 --- a/sys/js/callback.c +++ b/sys/js/callback.c @@ -19,7 +19,7 @@ static void js_event_callback(event_t *event) void js_callback_init(js_callback_t *js_callback, jerry_value_t callback) { DEBUG("init %p\n", js_callback); - js_callback->event.callback = js_event_callback; + js_callback->event.handler = js_event_callback; DEBUG("acquire obj %lu\n", js_callback->callback.object); js_native_ref_add(&js_callback->callback, callback); From df8dae980d7eb39549766fd41e510379682556c0 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Tue, 24 Oct 2017 12:02:31 +0200 Subject: [PATCH 17/17] sys/js: export js_add_external_handler() --- sys/include/js.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/include/js.h b/sys/include/js.h index 206898886ba4..c10333b87305 100644 --- a/sys/include/js.h +++ b/sys/include/js.h @@ -35,6 +35,7 @@ int js_run(const jerry_char_t *script, size_t script_size); void js_native_ref_add(js_native_ref_t *ref, jerry_value_t object); void js_native_ref_rem(js_native_ref_t *ref); void js_init_objects(void); +void js_add_external_handler(jerry_value_t object, const char *name, jerry_external_handler_t handler); void js_add_object(jerry_value_t object, jerry_value_t other, const char *name); void *js_get_object_native_pointer(jerry_value_t object, const jerry_object_native_info_t *type); jerry_value_t js_object_create_with_methods(const js_native_method_t *methods, unsigned num_methods);