V7_PRIVATE val_t Regex_ctor(struct v7 *v7, val_t this_obj, val_t args) { long argnum = v7_array_length(v7, args); if (argnum > 0) { val_t ro = to_string(v7, v7_array_get(v7, args, 0)); size_t re_len, flags_len = 0; const char *re = v7_to_string(v7, &ro, &re_len), *flags = NULL; struct slre_prog *p = NULL; struct v7_regexp *rp; (void) this_obj; if (argnum > 1) { val_t fl = to_string(v7, v7_array_get(v7, args, 1)); flags = v7_to_string(v7, &fl, &flags_len); } if (slre_compile(re, re_len, flags, flags_len, &p, 1) != SLRE_OK || p == NULL) { throw_exception(v7, TYPE_ERROR, "Invalid regex"); return v7_create_undefined(); } else { rp = (struct v7_regexp *) malloc(sizeof(*rp)); rp->regexp_string = v7_create_string(v7, re, re_len, 1); rp->compiled_regexp = p; rp->lastIndex = 0; return v7_pointer_to_value(rp) | V7_TAG_REGEXP; } } return v7_create_regexp(v7, "(?:)", 4, NULL, 0); }
static v7_val_t Http_post(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t urlv = v7_array_get(v7, args, 0); v7_val_t body = v7_array_get(v7, args, 1); v7_val_t cb = v7_array_get(v7, args, 2); (void) this_obj; return Http_call(v7, urlv, body, cb, "POST"); }
ICACHE_FLASH_ATTR static v7_val_t Wifi_setup(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { struct station_config stationConf; v7_val_t ssidv = v7_array_get(v7, args, 0); v7_val_t passv = v7_array_get(v7, args, 1); const char *ssid, *pass; size_t ssid_len, pass_len; int res; if (!v7_is_string(ssidv) || !v7_is_string(passv)) { printf("ssid/pass are not strings\n"); return v7_create_undefined(); } wifi_station_disconnect(); ssid = v7_to_string(v7, &ssidv, &ssid_len); pass = v7_to_string(v7, &passv, &pass_len); stationConf.bssid_set = 0; strncpy((char *) &stationConf.ssid, ssid, 32); strncpy((char *) &stationConf.password, pass, 64); res = v7_create_boolean(wifi_station_set_config(&stationConf)); if (!res) { printf("Failed to set station config\n"); return v7_create_boolean(0); } return v7_create_boolean(wifi_station_connect()); }
static v7_val_t js_sum(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { double arg0 = v7_to_number(v7_array_get(v7, args, 0)); double arg1 = v7_to_number(v7_array_get(v7, args, 1)); double result = sum(arg0, arg1); (void) this_obj; /* unused */ return v7_create_number(result); }
/* 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(); }
/* * Construct a new WebSocket object: * * url: url where to connect to * protocol: websocket subprotocol * * Example: * ws = new WebSocket('wss://localhost:1234'); * ws.onopen = function(ev) { * print("ON OPEN", ev); * } * * ws.onclose = function(ev) { * print("ON CLOSE", ev); * } * * ws.onmessage = function(ev) { * print("ON MESSAGE", ev); * } * * ws.onerror = function(ev) { * print("ON ERROR", ev); * } * */ static v7_val_t sj_ws_ctor(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { struct mg_connection *nc; struct user_data *ud; v7_val_t urlv = v7_array_get(v7, args, 0); v7_val_t subprotov = v7_array_get(v7, args, 1); (void) this_obj; (void) args; if (!v7_is_string(urlv)) { v7_throw(v7, "invalid ws url string"); } if (v7_is_object(this_obj) && this_obj != v7_get_global_object(v7)) { int use_ssl = 0; size_t len; const char *url = v7_to_string(v7, &urlv, &len); if (strncmp(url, "ws://", 5) == 0) { url += 5; } else if (strncmp(url, "wss://", 6) == 0) { url += 6; use_ssl = 1; } nc = mg_connect(&sj_mgr, url, ws_ev_handler); if (nc == NULL) v7_throw(v7, "error creating the connection"); #ifdef NS_ENABLE_SSL if (use_ssl) { mg_set_ssl(nc, NULL, NULL); } #endif (void) use_ssl; mg_set_protocol_http_websocket(nc); ud = calloc(1, sizeof(*ud)); ud->v7 = v7; ud->ws = this_obj; nc->user_data = ud; v7_own(v7, &ud->ws); if (v7_is_string(subprotov)) { size_t len; const char *proto = v7_to_string(v7, &subprotov, &len); ud->proto = strdup(proto); } } else { v7_throw(v7, "WebSocket ctor called without new"); } return v7_create_undefined(); }
static v7_val_t GPIO_write(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 valv = v7_array_get(v7, args, 1); int pin, val; if (!v7_is_number(pinv)) { printf("non-numeric pin\n"); return v7_create_undefined(); } pin = v7_to_number(pinv); val = v7_to_number(valv); return v7_create_boolean(sj_gpio_write(pin, val) == 0); }
static v7_val_t dsleep(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t time_v = v7_array_get(v7, args, 0); uint32 time = v7_to_number(time_v); v7_val_t flags_v = v7_array_get(v7, args, 1); uint8 flags = v7_to_number(flags_v); if (!v7_is_number(time_v) || time < 0) return v7_create_boolean(false); if (v7_is_number(flags_v)) { if (!system_deep_sleep_set_option(flags)) return v7_create_boolean(false); } system_deep_sleep(time); return v7_create_boolean(true); }
static v7_val_t WebSocket_send(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t datav = v7_array_get(v7, args, 0); v7_val_t ncv = v7_get(v7, this_obj, "_nc", ~0); struct mg_connection *nc; /* * TODO(alashkin): check why v7_is_instanceof throws exception * in case of string */ int is_blob = !v7_is_string(datav) && v7_is_instanceof(v7, datav, "Blob"); if (!v7_is_string(datav) && !is_blob) { v7_throw(v7, "arg should be string or Blob"); return v7_create_undefined(); } if (!v7_is_foreign(ncv) || (nc = (struct mg_connection *) v7_to_foreign(ncv)) == NULL) { v7_throw(v7, "ws not connected"); return v7_create_undefined(); } if (is_blob) { _WebSocket_send_blob(v7, nc, datav); } else { _WebSocket_send_string(v7, nc, datav); } return v7_create_undefined(); }
static val_t Json_stringify(struct v7 *v7, val_t this_obj, val_t args) { val_t arg0 = v7_array_get(v7, args, 0); char buf[100], *p = v7_to_json(v7, arg0, buf, sizeof(buf)); val_t res = v7_create_string(v7, p, strlen(p), 1); (void) this_obj; if (p != buf) free(p); return res; }
static v7_val_t GPIO_setmode(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 modev = v7_array_get(v7, args, 1); v7_val_t pullv = v7_array_get(v7, args, 2); int pin, mode, pull; if (!v7_is_number(pinv) || !v7_is_number(modev) || !v7_is_number(pullv)) { printf("Invalid arguments"); return v7_create_undefined(); } pin = v7_to_number(pinv); mode = v7_to_number(modev); pull = v7_to_number(pullv); return v7_create_boolean(sj_gpio_set_mode(pin, mode, pull) == 0); }
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); }
ICACHE_FLASH_ATTR static v7_val_t GPIO_out(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 valv = v7_array_get(v7, args, 1); int pin, val; if (!v7_is_double(pinv)) { printf("non-numeric pin\n"); return v7_create_undefined(); } pin = v7_to_double(pinv); val = v7_is_true(v7, valv) ? 1 : 0; set_gpio(pin, val); return v7_create_undefined(); }
/* * Start dummy TCP generator server. * * port: tcp port to listen to */ static v7_val_t Tcp_gen(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t port = v7_array_get(v7, args, 0); if (!v7_is_number(port)) { printf("bad port number\n"); return v7_create_undefined(); } start_data_gen_server(v7_to_number(port)); return v7_create_undefined(); }
static v7_val_t global_usleep(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t usecsv = v7_array_get(v7, args, 0); int usecs; if (!v7_is_number(usecsv)) { printf("usecs is not a double\n\r"); return v7_create_undefined(); } usecs = v7_to_number(usecsv); sj_usleep(usecs); return v7_create_undefined(); }
ICACHE_FLASH_ATTR static v7_val_t GPIO_in(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t pinv = v7_array_get(v7, args, 0); int pin; if (!v7_is_double(pinv)) { printf("non-numeric pin\n"); return v7_create_undefined(); } pin = v7_to_double(pinv); return v7_create_boolean(read_gpio_pin(pin)); }
ICACHE_FLASH_ATTR static v7_val_t usleep(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t usecsv = v7_array_get(v7, args, 0); int usecs; if (!v7_is_double(usecsv)) { printf("usecs is not a double\n\r"); return v7_create_undefined(); } usecs = v7_to_double(usecsv); os_delay_us(usecs); return v7_create_undefined(); }
static v7_val_t GPIO_read(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t pinv = v7_array_get(v7, args, 0); int pin; if (!v7_is_number(pinv)) { printf("non-numeric pin\n"); return v7_create_undefined(); } pin = v7_to_number(pinv); return v7_create_number(sj_gpio_read(pin)); }
/* * Prints message to current debug output */ v7_val_t Debug_print(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { int i, num_args = v7_array_length(v7, args); (void) this_obj; for (i = 0; i < num_args; i++) { v7_fprint(stderr, v7, v7_array_get(v7, args, i)); fprintf(stderr, " "); } fprintf(stderr, "\n"); return v7_create_undefined(); }
/* HAL functions */ spi_connection sj_spi_create(struct v7 *v7, v7_val_t args) { struct lnx_spi_connection *conn; v7_val_t spi_no_val = v7_array_get(v7, args, 0); double spi_no = v7_to_number(spi_no_val); ; if (!v7_is_number(spi_no_val) || spi_no < 0) { v7_throw(v7, "Missing arguments for SPI number or wrong type."); } conn = malloc(sizeof(*conn)); conn->spi_no = v7_to_number(spi_no); return conn; }
/* Currently can only handle one timer */ static v7_val_t global_set_timeout(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t *cb; v7_val_t msecsv = v7_array_get(v7, args, 1); int msecs; cb = (v7_val_t *) malloc(sizeof(*cb)); v7_own(v7, cb); *cb = v7_array_get(v7, args, 0); if (!v7_is_function(*cb)) { printf("cb is not a function\n"); return v7_create_undefined(); } if (!v7_is_number(msecsv)) { printf("msecs is not a double\n"); return v7_create_undefined(); } msecs = v7_to_number(msecsv); sj_set_timeout(msecs, cb); return v7_create_undefined(); }
/* * Sets output for debug messages. * Available modes are: * 0 - no debug output * 1 - print debug output to UART0 (V7's console) * 2 - print debug output to UART1 */ static v7_val_t Debug_mode(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { int mode, res; v7_val_t output_val = v7_array_get(v7, args, 0); if (!v7_is_number(output_val)) { printf("Output is not a number\n"); return v7_create_undefined(); } mode = v7_to_number(output_val); uart_debug_init(0, 0); res = uart_redirect_debug(mode); return v7_create_number(res < 0 ? res : mode); }
static enum v7_err isr_cb_proxy(struct v7 *v7, v7_val_t *res) { v7_val_t cb = v7_arg(v7, 0); v7_val_t args = v7_arg(v7, 1); v7_own(v7, &cb); v7_own(v7, &args); enum v7_err ret = v7_apply(v7, cb, v7_get_global(v7), args, res); sj_reenable_intr(v7_get_double(v7, v7_array_get(v7, args, 0))); v7_disown(v7, &args); v7_disown(v7, &cb); return ret; }
/* * Returns the IP address of an interface. * * Pass either Wifi.STATION or Wifi.SOFTAP * Defaults to Wifi.STATION if called without argument. */ ICACHE_FLASH_ATTR static v7_val_t Wifi_ip(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t arg = v7_array_get(v7, args, 0); int err; struct ip_info info; char ip[17]; (void) this_obj; (void) args; err = wifi_get_ip_info(v7_is_double(arg) ? v7_to_double(arg) : 0, &info); if (err == 0) { v7_throw(v7, "cannot get ip info"); } snprintf(ip, sizeof(ip), IPSTR, IP2STR(&info.ip)); return v7_create_string(v7, ip, strlen(ip), 1); }
static v7_val_t DHT11_read(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { int pin, temp, rh; v7_val_t pinv = v7_array_get(v7, args, 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; }
ICACHE_FLASH_ATTR static v7_val_t DHT11_read(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { int pin, temp, rh; v7_val_t pinv = v7_array_get(v7, args, 0), result; if (!v7_is_double(pinv)) { printf("non-numeric pin\n"); return v7_create_undefined(); } pin = v7_to_double(pinv); if (!dht11_read(pin, &temp, &rh)) { return v7_create_null(); } result = v7_create_object(v7); v7_set(v7, result, "temp", 4, 0, v7_create_number(temp)); v7_set(v7, result, "rh", 2, 0, v7_create_number(rh)); /* prevent the object from being potentially GCed */ v7_set(v7, args, "_tmp", 4, 0, result); return result; }
int v7_example(void) { size_t n; const char *domain_str; struct v7 *v7 = v7_create(); v7_val_t domain, port0, config; /* Load JSON configuration */ if (v7_parse_json_file(v7, "config.json", &config) != V7_OK) { printf("%s\n", "Cannot load JSON config"); return 1; } /* Lookup values in JSON configuration object */ domain = v7_get(v7, config, "domain", 6); port0 = v7_array_get(v7, v7_get(v7, config, "ports", 5), 0); domain_str = v7_get_string(v7, &domain, &n); printf("Domain: [%.*s], port 0: [%d]\n", (int) n, domain_str, (int) v7_get_double(port0)); v7_destroy(v7); return 0; }
static v7_val_t WebSocket_send(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { v7_val_t datav = v7_array_get(v7, args, 0); v7_val_t ncv = v7_get(v7, this_obj, "_nc", ~0); struct ns_connection *nc; const char *data; size_t len; if (!v7_is_string(datav)) { v7_throw(v7, "non string data not implemented"); return v7_create_undefined(); } if (!v7_is_foreign(ncv) || (nc = (struct ns_connection *) v7_to_foreign(ncv)) == NULL) { v7_throw(v7, "ws not connected"); return v7_create_undefined(); } data = v7_to_string(v7, &datav, &len); ns_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, data, len); return v7_create_undefined(); }
static void _WebSocket_send_blob(struct v7 *v7, struct mg_connection *nc, v7_val_t blob) { const char *data; size_t len; unsigned long alen, i; v7_val_t chunks, chunk; chunks = v7_get(v7, blob, "a", ~0); alen = v7_array_length(v7, chunks); for (i = 0; i < alen; i++) { int op = i == 0 ? WEBSOCKET_OP_BINARY : WEBSOCKET_OP_CONTINUE; int flag = i == alen - 1 ? 0 : WEBSOCKET_DONT_FIN; chunk = v7_array_get(v7, chunks, i); /* * This hack allows us to skip the first or the last frame * while sending blobs. The effect of it is that it's possible to * concatenate more blobs into a single WS message composed of * several fragments. * * WebSocket.send(new Blob(["123", undefined])); * WebSocket.send(new Blob([undefined, "456"])); * * If the last blob component is undefined, the current message is thus * left open. In order to continue sending fragments of the same message * the next send call should have it's first component undefined. * * TODO(mkm): find a better API. */ if (!v7_is_undefined(chunk)) { data = v7_to_string(v7, &chunk, &len); mg_send_websocket_frame(nc, op | flag, data, len); } } }
/* * Prints message to current debug output */ ICACHE_FLASH_ATTR v7_val_t Debug_print(struct v7 *v7, v7_val_t this_obj, v7_val_t args) { char *p, buf[512]; int i, num_args = v7_array_length(v7, args); (void) this_obj; for (i = 0; i < num_args; i++) { v7_val_t arg = v7_array_get(v7, args, i); if (v7_is_string(arg)) { size_t n; const char *s = v7_to_string(v7, &arg, &n); os_printf("%s", s); } else { p = v7_to_json(v7, arg, buf, sizeof(buf)); os_printf("%s", p); if (p != buf) { free(p); } } } os_printf("\n"); return v7_create_null(); }