low.js native API
- low.js Professional on ESP32 (see Store)
- low.js for PC on Linux x86, x86_64 and ARMv8
The native modules are written with the low native API, which consists of
- low.js specific functions
- parts of the DukTape API
- the C++ Standard Library
- parts of the C POSIX library
For all functions, see API reference below.
A very simple example can be found on GitHub.Walkthrough of this example:
- native.cpp is compiled into the module file native.so by the Makefile. You get the version for the PC by just calling make, the ESP32 version by calling make esp32
- index.js now simply requires the native module and calls the function
Important notes on the architecture
Linker script / Memory modelNative modules have to be linked with the settings and the linker script with is already used in the Makefile of the supplied example. Please copy these into your own Makefile / build environment. On the ESP32, the native modules run from Flash. IRAM is not used.
DukTape / low.js context
low_context, defined in low.h, is a typedef of duk_context, and thus means the same thing. There is only one duk_context/low_context pointer for a given program.The additional low.js functions can often be called from any thread, however, while the DukTape functions may only be called from the code thread.
Module loading / unloading functions
Defined in low.h
__attribute__ ((visibility ("default"))) bool module_unload();When a module is unloaded, the function module_unload is called. This happens when the user program is exiting. DukTape is already deinitialized and all your finalizers were called. Here you must deallocate all memory allocated in the module. Failure of doing this will result into memory leaks, as on ESP32 the microcontroller is not reset between runs of the user program.
low.js uses at least three threads.The code thread
This is where work is done which should run asyncronly. For example, all file operations which are scheduled are done in this thread. On the PC, multiple worker threads may exist, so multiple scheduled operations can run at the same time. The immediate thread
In this thread, only things should be done, which do not block. For example, HTTP/SSL operations happen here.
How to implement asynchronous functions with callback
The low.js specific functions
Defined in low.h
void low_load_module(duk_context *ctx, const char *path, bool parent_on_stack);
require() a module. If you have access to your module object (put on stash with low_add_stash in module_load for example), put it on the top of your stack before calling low_load_module and call it with parent_on_stack set to true. If you do not do this, the module’s parent will not be set correctly (which might be fine most of the time).
void low_call_thread(duk_context *ctx, low_thread thread, int priority, void (*func)(low_context *ctx, void *userdata), void *userdata);
The given callback will be called with the given user data from the given thread. As thread, you may give:
With LOW_THREAD_WORKER, you can give different priorities. Use 0 for faster workers, 1 for slower workers. As a reference: low.js itself uses 0 for reading files, 1 for writing files, which for example keeps the neonious IDE more responsive even when saving files.
low_thread low_get_current_thread(duk_context *ctx);
Returns the thread you are calling this function from. Return value is one of:
int low_set_timeout(duk_context *ctx, int index, int delay, void (*call)(low_context *ctx, void *userdata), void *data);
Must only be called from the code thread!Schedules a callback to be called with the given user data after the delay specified in milliseconds. If this shall be a new timeout, set index to 0, otherwise set index to the value returned by the previous low_set_timeout. This function will return the index of the scheduled call, which is never 0 and equal to the index given if it was not 0 (which means schedule a new call).
void low_clear_timeout(duk_context *ctx, int index);
Must only be called from the code thread!Clears a callback call scheduled with low_set_timeout.
void low_call_next_tick(duk_context *ctx, int num_args);
int low_add_stash(duk_context *ctx, int index);
Must only be called from the code thread!Adds a variable from the DukTape stack to the stash, saving it for future use even after the current call ends. Useful to save callbacks. With the variable on the stash, you can add it back to the DukTape stack by calling low_push_stash with the return value of low_add_stash later.
void low_remove_stash(duk_context *ctx, int index);
Must only be called from the code thread!Removes a variable from the DukTape stack.
void low_push_stash(duk_context *ctx, int index, bool remove);
Pushes a variable from the stash to the DukTape stack. If the function is called with remove set to true, the variable will be removed from the stash.
void *low_push_buffer(duk_context *ctx, int len);
Must only be called from the code thread!Creates a new buffer and pushes it on the DukTape stack. The buffer has all properties of a regular Node.JS Buffer. This function call returns a pointer to the data of the buffer. This function throws if memory is full.
void low_push_error(duk_context *ctx, int error, const char *syscall);
Must only be called from the code thread!Creates a Node.JS type error with error code and error message. Error is the errno which happened, syscall is the name of the function which resulted in the error.
void *low_alloc_throw(duk_context *ctx, size_t size);
Must only be called from the code thread!Same as malloc, but throws an DukTape error if memory is full.
Available functions of DukTape API
Please note that duk_require_... functions are not exported so errors have to be actively handled.
duk_api_global_filename duk_api_global_line duk_base64_decode duk_base64_encode duk_buffer_to_string duk_call duk_call_method duk_call_prop duk_char_code_at duk_check_type duk_check_type_mask duk_components_to_time duk_concat duk_copy duk_decode_string duk_def_prop duk_del_prop duk_del_prop_index duk_del_prop_literal_raw duk_del_prop_lstring duk_del_prop_string duk_dup duk_dup_top duk_enum duk_equals duk_error_raw duk_freeze duk_generic_error_stash duk_get_boolean duk_get_boolean_default duk_get_buffer_data duk_get_buffer_data_default duk_get_c_function duk_get_c_function_default duk_get_finalizer duk_get_int duk_get_int_default duk_get_length duk_get_lstring duk_get_lstring_default duk_get_now duk_get_number duk_get_number_default duk_get_pointer duk_get_pointer_default duk_get_prop duk_get_prop_desc duk_get_prop_index duk_get_prop_literal_raw duk_get_prop_lstring duk_get_prop_string duk_get_prototype duk_get_string duk_get_string_default duk_get_top duk_get_top_index duk_get_type duk_get_type_mask duk_get_uint duk_get_uint_default duk_has_prop duk_has_prop_index duk_has_prop_literal_raw duk_has_prop_lstring duk_has_prop_string duk_hex_decode duk_hex_encode duk_insert duk_instanceof duk_is_array duk_is_boolean duk_is_buffer_data duk_is_c_function duk_is_constructable duk_is_constructor_call duk_is_function duk_is_nan duk_is_null duk_is_number duk_is_object duk_is_pointer duk_is_string duk_is_symbol duk_is_undefined duk_is_valid_index duk_join duk_json_decode duk_json_encode duk_map_string duk_new duk_next duk_normalize_index duk_pop duk_pop_2 duk_pop_3 duk_pop_n duk_push_array duk_push_boolean duk_push_c_function duk_push_current_function duk_push_error_object_raw duk_push_false duk_push_int duk_push_literal_raw duk_push_lstring duk_push_nan duk_push_new_target duk_push_null duk_push_number duk_push_object duk_push_pointer duk_push_proxy duk_push_sprintf duk_push_string duk_push_this duk_push_true duk_push_uint duk_push_undefined duk_put_function_list duk_put_number_list duk_put_prop duk_put_prop_index duk_put_prop_literal_raw duk_put_prop_lstring duk_put_prop_string duk_random duk_remove duk_replace duk_samevalue duk_seal duk_set_finalizer duk_set_length duk_set_prototype duk_set_top duk_strict_equals duk_substring duk_swap duk_swap_top duk_throw_raw duk_time_to_components duk_to_boolean duk_to_int duk_to_int32 duk_to_lstring duk_to_null duk_to_number duk_to_object duk_to_pointer duk_to_primitive duk_to_string duk_to_uint duk_to_uint16 duk_to_uint32 duk_to_undefined duk_trim
Available functions of C POSIX on ESP32
This list will be extended over time and on request (ask in the Forum). On the PC all functions are available which can be dynamically loaded.
abs acos asin atan atan2 atoi ceil close copysign cos difftime div environ exp fabs fclose ferror fflush fgets finite fiprintf floor fmod fopen fprintf fputwc fread free frexp fseek fseeko fstat fwrite getenv getpid gettimeofday gmtime_r index isalnum isspace iswspace labs localeconv localtime_r log lseek matherr mbrtowc memchr memcmp memcpy memmove memset mktime nan nanf open pow printf putc putchar puts qsort rand read rename rint scalbn setlocale sin sniprintf snprintf sprintf sqrt srand sscanf stat strcasecmp strchr strcmp strcpy strdup strerror strftime strlcat strlcpy strlen strncasecmp strncmp strncpy strnlen strptime strrchr strstr strtod strtof strtok_r strtol strtoul tan time tolower toupper ungetc unlink vfiprintf vfprintf vprintf vsnprintf wcrtomb write