static enum v7_err Sys_prof(struct v7 *v7, v7_val_t *res) { *res = v7_mk_object(v7); v7_set(v7, *res, "sysfree", ~0, v7_mk_number(v7, sj_get_free_heap_size())); v7_set(v7, *res, "min_sysfree", ~0, v7_mk_number(v7, sj_get_min_free_heap_size())); v7_set(v7, *res, "used_by_js", ~0, v7_mk_number(v7, v7_heap_stat(v7, V7_HEAP_STAT_HEAP_USED))); v7_set(v7, *res, "used_by_fs", ~0, v7_mk_number(v7, sj_get_fs_memory_usage())); return V7_OK; }
static v7_val_t OS_prof(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t result = v7_create_object(v7); v7_own(v7, &result); v7_set(v7, result, "sysfree", 7, 0, v7_create_number(sj_get_free_heap_size())); v7_set(v7, result, "used_by_js", 10, 0, v7_create_number(v7_heap_stat(v7, V7_HEAP_STAT_HEAP_USED))); v7_set(v7, result, "used_by_fs", 10, 0, v7_create_number(sj_get_fs_memory_usage())); v7_disown(v7, &result); return result; }
int main(void) { enum v7_err rcode = V7_OK; struct v7 *v7 = v7_create(); v7_val_t ctor_func, proto, eval_result; proto = v7_mk_object(v7); ctor_func = v7_mk_function_with_proto(v7, MyThing_ctor, proto); v7_def(v7, ctor_func, "MY_CONST", ~0, (V7_DESC_WRITABLE(0) | V7_DESC_CONFIGURABLE(0)), v7_mk_number(123)); v7_set_method(v7, proto, "myMethod", &MyThing_myMethod); v7_set(v7, v7_get_global(v7), "MyThing", ~0, ctor_func); rcode = v7_exec(v7, "\ print('MyThing.MY_CONST = ', MyThing.MY_CONST); \ var t = new MyThing(456); \ print('t.MY_CONST = ', t.MY_CONST); \ print('t.myMethod = ', t.myMethod); \ print('t.myMethod() = ', t.myMethod());", &eval_result); if (rcode != V7_OK) { fprintf(stderr, "exec error: %d\n", (int) rcode); } v7_destroy(v7); return (int) rcode; }
SJ_PRIVATE enum v7_err Http_response_writeHead(struct v7 *v7, v7_val_t *res) { enum v7_err rcode = V7_OK; DECLARE_CONN(); unsigned long code = 200; v7_val_t arg0 = v7_arg(v7, 0), arg1 = v7_arg(v7, 1); if (v7_is_truthy(v7, v7_get(v7, v7_get_this(v7), "_whd", ~0))) { rcode = v7_throwf(v7, "Error", "Headers already sent"); goto clean; } if (v7_is_number(arg0)) { code = v7_to_number(arg0); } write_http_status(c, code); http_write_headers(v7, arg1, c); mg_send(c, "\r\n", 2); v7_set(v7, v7_get_this(v7), "_whd", ~0, v7_mk_boolean(1)); *res = v7_get_this(v7); clean: return rcode; }
enum v7_err v7_set_str(struct v7 *v7, struct v7_val *obj, const char *key, const char *str, unsigned long len) { struct v7_val *k = v7_mkval_str(v7, key, strlen(key)); struct v7_val *v = v7_mkval_str(v7, str, len); CHECK(k != NULL && v != NULL, V7_OUT_OF_MEMORY); return v7_set(v7, obj, k, v); }
/* Currently can only handle one timer */ ICACHE_FLASH_ATTR static v7_val_t set_timeout(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t cb = v7_array_get(v7, args, 0); v7_val_t msecsv = v7_array_get(v7, args, 1); int msecs; if (!v7_is_function(cb)) { printf("cb is not a function\n"); return v7_create_undefined(); } if (!v7_is_double(msecsv)) { printf("msecs is not a double\n"); return v7_create_undefined(); } msecs = v7_to_double(msecsv); /* * used to convey the callback to the timer handler _and_ to root * the function so that the GC doesn't deallocate it. */ v7_set(v7, v7_get_global_object(v7), "_js_timeout_handler", 19, 0, cb); os_timer_disarm(&js_timeout_timer); os_timer_setfn(&js_timeout_timer, js_timeout, NULL); os_timer_arm(&js_timeout_timer, msecs, 0); return v7_create_undefined(); }
void sj_init_ws_client(struct v7 *v7) { v7_val_t ws_proto = v7_create_object(v7); v7_val_t ws = v7_create_constructor(v7, ws_proto, sj_ws_ctor, 1); v7_own(v7, &ws); v7_set_method(v7, ws_proto, "send", WebSocket_send); v7_set_method(v7, ws_proto, "close", WebSocket_close); v7_set(v7, ws_proto, "readyState", ~0, V7_PROPERTY_DONT_ENUM | V7_PROPERTY_GETTER, v7_create_function(v7, WebSocket_readyState, 0)); v7_set(v7, ws, "OPEN", ~0, 0, WEBSOCKET_OPEN); v7_set(v7, ws, "CLOSED", ~0, 0, WEBSOCKET_CLOSED); v7_set(v7, v7_get_global_object(v7), "WebSocket", ~0, 0, ws); v7_disown(v7, &ws); }
void sj_init_uart(struct v7 *v7) { v7_val_t uart = V7_UNDEFINED, uart_proto = V7_UNDEFINED, uart_ctor = V7_UNDEFINED; v7_own(v7, &uart); v7_own(v7, &uart_proto); v7_own(v7, &uart_ctor); uart = v7_mk_object(v7); uart_proto = v7_mk_object(v7); uart_ctor = v7_mk_function_with_proto(v7, UART_ctor, uart_proto); v7_def(v7, uart, "dev", ~0, _V7_DESC_HIDDEN(1), uart_ctor); v7_set_method(v7, uart_proto, "read", UART_read); v7_set_method(v7, uart_proto, "write", UART_write); v7_set_method(v7, uart_proto, "recv", UART_recv); v7_set(v7, v7_get_global(v7), "UART", ~0, uart); { enum v7_err rcode = v7_exec( v7, "UART.open = function (d) { return new UART.dev(d); }", NULL); assert(rcode == V7_OK); #if defined(NDEBUG) (void) rcode; #endif } v7_disown(v7, &uart_ctor); v7_disown(v7, &uart_proto); v7_disown(v7, &uart); }
static v7_val_t Wifi_changed(struct v7 *v7) { v7_val_t cb = v7_arg(v7, 0); if (!v7_is_function(cb)) return v7_create_boolean(0); v7_set(v7, s_wifi, "_ccb", ~0, V7_PROPERTY_DONT_ENUM | V7_PROPERTY_HIDDEN, cb); return v7_create_boolean(1); }
enum v7_err v7_set_func(struct v7 *v7, struct v7_val *obj, const char *key, v7_func_t c_func) { struct v7_val *k = v7_mkval_str(v7, key, strlen(key)); struct v7_val *v = v7_mkval(v7, V7_C_FUNC); CHECK(k != NULL && v != NULL, V7_OUT_OF_MEMORY); v->v.c_func = c_func; return v7_set(v7, obj, k, v); }
enum v7_err v7_set_num(struct v7 *v7, struct v7_val *obj, const char *key, double num) { struct v7_val *k = v7_mkval_str(v7, key, strlen(key)); struct v7_val *v = v7_mkval(v7, V7_NUM); CHECK(k != NULL && v != NULL, V7_OUT_OF_MEMORY); v->v.num = num; return v7_set(v7, obj, k, v); }
void sj_sys_js_init(struct v7 *v7) { v7_val_t sys, fs; sys = v7_mk_object(v7); v7_set(v7, v7_get_global(v7), "Sys", ~0, sys); v7_set_method(v7, sys, "prof", Sys_prof); v7_set_method(v7, sys, "reboot", Sys_reboot); v7_set_method(v7, sys, "setLogLevel", Sys_setLogLevel); v7_set_method(v7, sys, "time", Sys_time); v7_set_method(v7, sys, "wdtFeed", Sys_wdtFeed); v7_set_method(v7, sys, "wdtSetTimeout", Sys_wdtSetTimeout); v7_set_method(v7, sys, "wdtEnable", Sys_wdtEnable); v7_set_method(v7, sys, "wdtDisable", Sys_wdtDisable); fs = v7_mk_object(v7); v7_set(v7, sys, "fs", ~0, fs); v7_set_method(v7, fs, "free", Sys_fs_getFreeSpace); }
static v7_val_t GPIO_setisr(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t pinv = v7_array_get(v7, args, 0); v7_val_t typev = v7_array_get(v7, args, 1); v7_val_t cb = v7_array_get(v7, args, 2); v7_val_t current_cb; char prop_name[15]; int pin, type, len, has_isr, new_isr_provided; if (!v7_is_number(pinv) || !v7_is_number(typev)) { printf("Invalid arguments\n"); return v7_create_boolean(0); } pin = v7_to_number(pinv); type = v7_to_number(typev); len = snprintf(prop_name, sizeof(prop_name), "_ih_%d", (int) pin); current_cb = v7_get(v7, v7_get_global_object(v7), prop_name, len); has_isr = v7_is_function(current_cb); new_isr_provided = v7_is_function(cb); if (!has_isr && !new_isr_provided) { printf("Missing callback\n"); return v7_create_boolean(0); }; if (has_isr && new_isr_provided && current_cb != cb) { printf("Only one interruption handler is allowed for pin\n"); return v7_create_boolean(0); } if (type == 0 && has_isr) { v7_set(v7, v7_get_global_object(v7), prop_name, len, 0, v7_create_undefined()); } else if (!has_isr && new_isr_provided) { v7_set(v7, v7_get_global_object(v7), prop_name, len, 0, cb); } if (type != 0 && !s_gpio_intr_installed) { sj_gpio_intr_init(gpio_intr_handler_proxy); s_gpio_intr_installed = 1; } return v7_create_boolean(sj_gpio_intr_set(pin, type) == 0); }
void sj_init_simple_http_client(struct v7 *v7) { v7_val_t http; http = v7_create_object(v7); v7_set(v7, v7_get_global_object(v7), "Http", 4, 0, http); v7_set_method(v7, http, "get", sj_http_get); v7_set_method(v7, http, "post", sj_http_post); }
void init_gpiojs(struct v7 *v7) { s_v7 = v7; v7_val_t gpio = v7_create_object(v7); v7_set(v7, v7_get_global(v7), "GPIO", ~0, 0, gpio); v7_set_method(v7, gpio, "setmode", GPIO_setmode); v7_set_method(v7, gpio, "read", GPIO_read); v7_set_method(v7, gpio, "write", GPIO_write); v7_set_method(v7, gpio, "setisr", GPIO_setisr); }
void miot_console_api_setup(struct v7 *v7) { v7_val_t console_v = v7_mk_object(v7); v7_own(v7, &console_v); v7_set_method(v7, console_v, "log", Console_log); v7_set(v7, v7_get_global(v7), "console", ~0, console_v); v7_disown(v7, &console_v); }
void sj_gpio_api_setup(struct v7 *v7) { s_v7 = v7; v7_val_t gpio = v7_mk_object(v7); v7_set(v7, v7_get_global(v7), "GPIO", ~0, gpio); v7_set_method(v7, gpio, "setmode", GPIO_setmode); v7_set_method(v7, gpio, "read", GPIO_read); v7_set_method(v7, gpio, "write", GPIO_write); v7_set_method(v7, gpio, "setisr", GPIO_setisr); }
static void ws_ev_handler(struct ns_connection *nc, int ev, void *ev_data) { struct websocket_message *wm = (struct websocket_message *) ev_data; struct user_data *ud = (struct user_data *) nc->user_data; struct v7 *v7 = ud->v7; switch (ev) { case NS_CONNECT: if (*(int *) ev_data == 0) { char *proto = NULL; if (ud->proto != NULL) { int tmp = asprintf(&proto, "Sec-WebSocket-Protocol: %s\n", ud->proto); (void) tmp; /* Shutup compiler */ } ns_send_websocket_handshake(nc, "/", proto); if (proto != NULL) { free(proto); } } else { invoke_cb(ud, "onerror", v7_create_null()); } break; case NS_WEBSOCKET_HANDSHAKE_DONE: v7_set(v7, ud->ws, "_nc", ~0, V7_PROPERTY_HIDDEN, v7_create_foreign(nc)); invoke_cb(ud, "onopen", v7_create_null()); break; case NS_WEBSOCKET_FRAME: { v7_val_t ev, data; ev = v7_create_object(v7); v7_own(v7, &ev); data = v7_create_string(v7, (char *) wm->data, wm->size, 1); v7_set(v7, ev, "data", ~0, 0, data); invoke_cb(ud, "onmessage", ev); v7_disown(v7, &ev); break; } case NS_CLOSE: invoke_cb(ud, "onclose", v7_create_null()); nc->user_data = NULL; v7_set(v7, ud->ws, "_nc", ~0, V7_PROPERTY_HIDDEN, v7_create_undefined()); v7_disown(v7, &ud->ws); free(ud); break; } }
// function_defition = "function" "(" func_params ")" "{" func_body "}" static enum v7_err parse_function_definition(struct v7 *v7, struct v7_val **v, int num_params) { int i = 0, old_no_exec = v7->no_exec, old_sp = v7->sp; const char *src = v7->cursor; // If 'v' (func to call) is NULL, that means we're just parsing function // definition to save it's body. v7->no_exec = v == NULL; TRY(match(v7, '(')); // Initialize new scope if (!v7->no_exec) { v7->current_scope++; CHECK(v7->current_scope < (int) ARRAY_SIZE(v7->scopes), V7_RECURSION_TOO_DEEP); CHECK(v7->scopes[v7->current_scope].v.props == NULL, V7_INTERNAL_ERROR); CHECK(v7->scopes[v7->current_scope].type == V7_OBJ, V7_INTERNAL_ERROR); } while (*v7->cursor != ')') { TRY(parse_identifier(v7)); if (!v7->no_exec) { struct v7_val *key = v7_mkval_str(v7, v7->tok, v7->tok_len); struct v7_val *val = i < num_params ? v[i + 1] : v7_mkval(v7, V7_UNDEF); v7_set(v7, &v7->scopes[v7->current_scope], key, val); } i++; if (!test_and_skip_char(v7, ',')) break; } TRY(match(v7, ')')); TRY(match(v7, '{')); while (*v7->cursor != '}') { int is_return_statement = 0; inc_stack(v7, old_sp - v7->sp); // Clean up the stack from prev stmt TRY(parse_statement(v7, &is_return_statement)); if (is_return_statement) break; // Leave statement value on stack } if (v7->no_exec) { TRY(v7_make_and_push(v7, V7_FUNC)); v7_top(v7)[-1]->v.func = v7_strdup(src, (v7->cursor + 1) - src); } TRY(match(v7, '}')); // Deinitialize scope if (!v7->no_exec) { v7->scopes[v7->current_scope].ref_count = 1; // Force free_val() below free_val(v7, &v7->scopes[v7->current_scope]); v7->current_scope--; assert(v7->current_scope >= 0); } v7->no_exec = old_no_exec; return V7_OK; }
void sj_init_v7_ext(struct v7 *v7) { v7_val_t os, gc; v7_set(v7, v7_get_global(v7), "version", 7, 0, v7_create_string(v7, sj_version, strlen(sj_version), 1)); v7_set_method(v7, v7_get_global(v7), "usleep", global_usleep); gc = v7_create_object(v7); v7_set(v7, v7_get_global(v7), "GC", 2, 0, gc); v7_set_method(v7, gc, "stat", GC_stat); v7_set_method(v7, gc, "gc", GC_gc); os = v7_create_object(v7); v7_set(v7, v7_get_global(v7), "OS", 2, 0, os); v7_set_method(v7, os, "prof", OS_prof); v7_set_method(v7, os, "wdt_feed", OS_wdt_feed); v7_set_method(v7, os, "reset", OS_reset); }
void sj_init_sys(struct v7 *v7) { v7_val_t sys; sys = v7_mk_object(v7); v7_set(v7, v7_get_global(v7), "Sys", ~0, sys); v7_set_method(v7, sys, "prof", Sys_prof); v7_set_method(v7, sys, "wdtFeed", Sys_wdtFeed); v7_set_method(v7, sys, "reboot", Sys_reboot); v7_set_method(v7, sys, "setLogLevel", Sys_setLogLevel); }
void sj_v7_ext_api_setup(struct v7 *v7) { v7_val_t gc; v7_set_method(v7, v7_get_global(v7), "usleep", global_usleep); gc = v7_mk_object(v7); v7_set(v7, v7_get_global(v7), "GC", ~0, gc); v7_set_method(v7, gc, "stat", GC_stat); v7_set_method(v7, gc, "gc", GC_gc); }
static enum v7_err UART_onTXEmpty(struct v7 *v7, v7_val_t *res) { struct esp_sj_uart_state *us; enum v7_err ret = esp_sj_uart_get_state(v7, &us); if (ret != V7_OK) return ret; v7_set(v7, us->obj, "_txcb", 5, v7_arg(v7, 0)); if (v7_is_callable(v7, v7_arg(v7, 0))) { esp_sj_uart_schedule_dispatcher(us->uart_no); } *res = v7_mk_undefined(); return V7_OK; }
static const char *test_native_functions(void) { struct v7_val *v; struct v7 *v7 = v7_create(); ASSERT(v7_set(v7, v7_global(v7), "adder", v7_push_func(v7, adder)) == V7_OK); ASSERT((v = v7_exec(v7, "adder(1, 2, 3 + 4);")) != NULL); ASSERT(check_num(v7, v, 10.0)); v7_destroy(&v7); return NULL; }
static v7_val_t gsm_on_incoming_call(struct v7* v7) { v7_val_t cb = v7_arg(v7, 0); if (!v7_is_function(cb)) { return v7_create_boolean(0); }; v7_set(v7, v7_get_global(v7), INCOMING_CALL_CB, sizeof(INCOMING_CALL_CB) - 1, 0, cb); return v7_create_boolean(1); }
void init_v7(void *stack_base) { struct v7_create_opts opts; v7_val_t dht11, debug; opts.object_arena_size = 164; opts.function_arena_size = 26; opts.property_arena_size = 400; opts.c_stack_base = stack_base; v7 = v7_create_opt(opts); v7_set_method(v7, v7_get_global(v7), "dsleep", dsleep); v7_set_method(v7, v7_get_global(v7), "crash", crash); #if V7_ESP_ENABLE__DHT11 dht11 = v7_create_object(v7); v7_set(v7, v7_get_global(v7), "DHT11", 5, 0, dht11); v7_set_method(v7, dht11, "read", DHT11_read); #else (void) dht11; #endif /* V7_ESP_ENABLE__DHT11 */ debug = v7_create_object(v7); v7_set(v7, v7_get_global(v7), "Debug", 5, 0, debug); v7_set_method(v7, debug, "mode", Debug_mode); v7_set_method(v7, debug, "print", Debug_print); sj_init_timers(v7); sj_init_v7_ext(v7); init_gpiojs(v7); init_i2cjs(v7); init_pwm(v7); init_spijs(v7); init_wifi(v7); mongoose_init(); sj_init_http(v7); sj_init_ws_client(v7); v7_gc(v7, 1); }
static v7_val_t DHT11_read(struct v7 *v7) { int pin, temp, rh; v7_val_t pinv = v7_arg(v7, 0), result; if (!v7_is_number(pinv)) { printf("non-numeric pin\n"); return v7_create_undefined(); } pin = v7_to_number(pinv); if (!dht11_read(pin, &temp, &rh)) { return v7_create_null(); } result = v7_create_object(v7); v7_own(v7, &result); v7_set(v7, result, "temp", 4, 0, v7_create_number(temp)); v7_set(v7, result, "rh", 2, 0, v7_create_number(rh)); v7_disown(v7, &result); return result; }
void sj_mqtt_api_setup(struct v7 *v7) { v7_val_t mqtt_proto = v7_mk_object(v7); v7_val_t mqtt_connect = v7_mk_function_with_proto(v7, sj_mqtt_connect, mqtt_proto); v7_val_t mqtt; v7_own(v7, &mqtt_connect); mqtt = v7_mk_object(v7); v7_own(v7, &mqtt); v7_set(v7, mqtt, "connect", ~0, mqtt_connect); v7_def(v7, mqtt, "proto", ~0, V7_DESC_ENUMERABLE(0), mqtt_proto); v7_set_method(v7, mqtt_proto, "publish", MQTT_publish); v7_set_method(v7, mqtt_proto, "subscribe", MQTT_subscribe); v7_set_method(v7, mqtt_proto, "on", MQTT_on); v7_set(v7, v7_get_global(v7), "MQTT", ~0, mqtt); v7_disown(v7, &mqtt); v7_disown(v7, &mqtt_connect); }
int main(void) { struct v7 *v7 = v7_create(); v7_val_t ctor_func, proto, eval_result; proto = v7_create_object(v7); ctor_func = v7_create_constructor(v7, proto, MyThing_ctor, 1); v7_set(v7, ctor_func, "MY_CONST", ~0, V7_PROPERTY_READ_ONLY | V7_PROPERTY_DONT_DELETE, v7_create_number(123)); v7_set_method(v7, proto, "myMethod", &MyThing_myMethod); v7_set(v7, v7_get_global_object(v7), "MyThing", ~0, 0, ctor_func); v7_exec(v7, &eval_result, "\ print('MyThing.MY_CONST = ', MyThing.MY_CONST); \ var t = new MyThing(456); \ print('t.MY_CONST = ', t.MY_CONST); \ print('t.myMethod = ', t.myMethod); \ print('t.myMethod() = ', t.myMethod());"); v7_destroy(v7); return 0; }
/* * Mongoose event handler. If JavaScript callback was provided, call it */ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { struct user_data *ud = (struct user_data *) c->user_data; if (ev == MG_EV_HTTP_REQUEST) { /* HTTP request has arrived */ if (v7_is_callable(ud->v7, ud->handler)) { /* call provided JavaScript callback with `request` and `response` */ v7_val_t request = v7_mk_object(ud->v7); v7_own(ud->v7, &request); v7_val_t response = v7_mk_object(ud->v7); v7_own(ud->v7, &response); setup_request_object(ud->v7, request, ev_data); setup_response_object(ud->v7, response, c, request); sj_invoke_cb2_this(ud->v7, ud->handler, ud->obj, request, response); v7_disown(ud->v7, &request); v7_disown(ud->v7, &response); } else { /* * no JavaScript callback provided; serve the request with the default * options by `mg_serve_http()` */ struct mg_serve_http_opts opts; memset(&opts, 0, sizeof(opts)); mg_serve_http(c, ev_data, opts); } } else if (ev == MG_EV_HTTP_REPLY) { /* HTTP response has arrived */ /* if JavaScript callback was provided, call it with `response` */ if (v7_is_callable(ud->v7, ud->handler)) { v7_val_t response = v7_mk_object(ud->v7); v7_own(ud->v7, &response); setup_request_object(ud->v7, response, ev_data); sj_invoke_cb1_this(ud->v7, ud->handler, ud->obj, response); v7_disown(ud->v7, &response); } if (c->flags & MG_F_CLOSE_CONNECTION_AFTER_RESPONSE) { c->flags |= MG_F_CLOSE_IMMEDIATELY; } } else if (ev == MG_EV_TIMER) { sj_invoke_cb0_this(ud->v7, ud->timeout_callback, ud->obj); } else if (ev == MG_EV_CLOSE) { if (c->listener == NULL && ud != NULL) { v7_set(ud->v7, ud->obj, "_c", ~0, v7_mk_undefined()); v7_disown(ud->v7, &ud->obj); v7_disown(ud->v7, &ud->timeout_callback); free(ud); c->user_data = NULL; } } }