├── mos_cc3220.yml ├── mos_esp32.yml ├── cc3220 └── fs │ └── api_arch_uart.js ├── esp8266 ├── fs │ ├── api_esp8266.js │ └── api_arch_uart.js └── src │ └── esp8266_mjs.c ├── README.md ├── mos_esp8266.yml ├── esp32 ├── fs │ ├── api_esp32.js │ └── api_arch_uart.js └── src │ └── esp32_mjs.c ├── LICENSE ├── mos.yml ├── fs ├── api_bitbang.js ├── polyfill.js ├── api_sys.js ├── api_timer.js ├── api_log.js ├── api_config.js ├── api_gpio.js ├── api_http.js ├── api_events.js ├── api_net.js └── api_uart.js ├── include └── mos_mjs.h └── src └── mos_mjs.c /mos_cc3220.yml: -------------------------------------------------------------------------------- 1 | filesystem: 2 | - cc3220/fs 3 | -------------------------------------------------------------------------------- /mos_esp32.yml: -------------------------------------------------------------------------------- 1 | sources: 2 | - esp32/src 3 | 4 | filesystem: 5 | - esp32/fs 6 | -------------------------------------------------------------------------------- /cc3220/fs/api_arch_uart.js: -------------------------------------------------------------------------------- 1 | UART._arch = { 2 | // Set arch-dependent UART config 3 | scfg: function(uartNo, cfg, param) { 4 | /* TODO */ 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /esp8266/fs/api_esp8266.js: -------------------------------------------------------------------------------- 1 | let ESP8266 = { 2 | // ## **`ESP8266.deepSleep(microseconds)`** 3 | // Deep Sleep given number of microseconds. 4 | // Return value: false on error, otherwise does not return. 5 | deepSleep: ffi('int mgos_system_deep_sleep_d(double)'), 6 | }; 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Embedded JavaScript engine 2 | 3 | This library brings an [mJS: restricted JavaScript-like 4 | Engine](https://github.com/cesanta/mjs). 5 | 6 | Apart from adding the mJS itself, the library creates a global instance of it 7 | (available via `mgos_mjs_get_global()`), and also brings a number of 8 | mgos-specific API files, see `fs` directory. 9 | -------------------------------------------------------------------------------- /mos_esp8266.yml: -------------------------------------------------------------------------------- 1 | sources: 2 | - esp8266/src 3 | 4 | filesystem: 5 | - esp8266/fs 6 | 7 | # Exclude api_dataview.js when flash size is small; otherwise fs doesn't fit 8 | conds: 9 | # TODO: when complex expressions are supported, check if FLASH_SIZE is 10 | # 1048576 or 2097152 11 | - when: defined(build_vars.FLASH_SIZE) 12 | apply: 13 | filesystem: 14 | - -${mos.modules.mjs_module.path}/mjs/lib/api_dataview.js 15 | -------------------------------------------------------------------------------- /esp32/fs/api_esp32.js: -------------------------------------------------------------------------------- 1 | let ESP32 = { 2 | // ## **`ESP32.temp()`** 3 | // Read built-in temperature sensor. Return value: integer. 4 | temp: ffi('int temprature_sens_read(void)'), 5 | 6 | // ## **`ESP32.hall()`** 7 | // Read built-in Hall sensor. Return value: integer. 8 | hall: ffi('int hall_sens_read(void)'), 9 | 10 | // ## **`ESP32.deepSleep(microseconds)`** 11 | // Deep Sleep given number of microseconds. 12 | // Return value: does not return. 13 | deepSleep: ffi('void mgos_esp_deep_sleep_d(double)'), 14 | }; 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Cesanta Software Limited 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /esp8266/fs/api_arch_uart.js: -------------------------------------------------------------------------------- 1 | UART._arch = { 2 | _usp: ffi('void esp_uart_config_set_params(void *, int, int, int, int, bool)'), 3 | 4 | // Set arch-dependent UART config 5 | scfg: function(uartNo, cfg, param) { 6 | if (param.esp8266 === undefined) return; 7 | 8 | let ep = param.esp8266; 9 | 10 | let ft = (ep.rxFullThresh !== undefined ? ep.rxFullThresh : -1); 11 | let fct = (ep.rxFcThresh !== undefined ? ep.rxFcThresh : -1); 12 | let alarm = (ep.rxAlarm !== undefined ? ep.rxAlarm : -1); 13 | let et = (ep.txEmptyThresh !== undefined ? ep.txEmptyThresh : -1); 14 | let swap = (ep.swapRxCtsTxRts !== undefined ? !!ep.swapRxCtsTxRts : false); 15 | 16 | this._usp(cfg, ft, fct, alarm, et, swap); 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /esp32/src/esp32_mjs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2018 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the ""License""); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an ""AS IS"" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | 20 | void mgos_esp_deep_sleep_d(double time_in_us) { 21 | esp_deep_sleep(time_in_us); 22 | } 23 | -------------------------------------------------------------------------------- /mos.yml: -------------------------------------------------------------------------------- 1 | author: mongoose-os 2 | description: JavaScript engine 3 | type: lib 4 | version: 1.0.0 5 | 6 | libs: 7 | - location: https://github.com/mongoose-os-libs/core 8 | 9 | modules: 10 | - location: https://github.com/cesanta/mjs 11 | name: mjs_module 12 | 13 | sources: 14 | - src 15 | - ${mos.modules.mjs_module.path}/mjs_no_common.c 16 | 17 | includes: 18 | - include 19 | - ${mos.modules.mjs_module.path} 20 | 21 | filesystem: 22 | - fs 23 | - ${mos.modules.mjs_module.path}/lib/api_*.js 24 | - "@all_libs/mjs_fs" 25 | 26 | config_schema: 27 | - ["mjs", "o", {title: "mJS settings"}] 28 | - ["mjs.generate_jsc", "b", true, {title: "Generate .jsc file when executing any .js file"}] 29 | 30 | tags: 31 | - js # Supports JavaScript 32 | - c 33 | - core 34 | - docs:misc:MJS JavaScript engine 35 | 36 | manifest_version: 2017-09-29 37 | -------------------------------------------------------------------------------- /fs/api_bitbang.js: -------------------------------------------------------------------------------- 1 | let BitBang = { 2 | DELAY_MSEC: 0, 3 | DELAY_USEC: 1, 4 | DELAY_100NSEC: 2, 5 | 6 | // ## **`BitBang.write(pin, delay_unit, t0h, t0l, t1h, t1l, ptr, len)`** 7 | // Write bits to a given `pin`. `delay_unit` is one of the: 8 | // `BitBang.DELAY_MSEC`, `BitBang.DELAY_USEC`, `BitBang.DELAY_100NSEC`. 9 | // `ptr, len` is a bit pattern to write. `t0h, t0l` is the time pattern 10 | // for zero bit, `t1h, t1l` is the time pattern for 1. The time pattern 11 | // specifies the number of time units to hold the pin high, and the number 12 | // of units to hold the pin low. Return value: none. 13 | write: function(pin, delay_unit, t0h, t0l, t1h, t1l, ptr, len) { 14 | let t = (t0h << 24) | (t0l << 16) | (t1h << 8) | t1l; 15 | this._wb(pin, delay_unit, t, ptr, len); 16 | }, 17 | 18 | _wb: ffi('void mgos_bitbang_write_bits_js(int, int, int, void *, int)'), 19 | }; 20 | -------------------------------------------------------------------------------- /esp8266/src/esp8266_mjs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2018 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the ""License""); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an ""AS IS"" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | 20 | int mgos_system_deep_sleep_d(double time_in_us) { 21 | wifi_station_disconnect(); 22 | wifi_set_opmode_current(NULL_MODE); 23 | return system_deep_sleep(time_in_us); 24 | } 25 | -------------------------------------------------------------------------------- /include/mos_mjs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2018 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the ""License""); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an ""AS IS"" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /* 19 | * mJS wrapper API. 20 | */ 21 | 22 | #ifndef MOS_MJS_H_ 23 | #define MOS_MJS_H_ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif /* __cplusplus */ 28 | 29 | #include "mjs.h" 30 | 31 | /* Return global mJS instance. */ 32 | struct mjs *mgos_mjs_get_global(void); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif /* __cplusplus */ 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /esp32/fs/api_arch_uart.js: -------------------------------------------------------------------------------- 1 | // esp32 architecture-dependent UART wrappers 2 | UART._arch = { 3 | _pins: ffi('void esp32_uart_config_set_pins(int, void *, int, int, int, int)'), 4 | _fifo: ffi('void esp32_uart_config_set_fifo(int, void *, int, int, int, int)'), 5 | 6 | // Set arch-dependent UART config 7 | scfg: function(uartNo, cfg, param) { 8 | if (param.esp32 === undefined) return; 9 | 10 | // Set GPIO params 11 | if (param.esp32.gpio !== undefined) { 12 | let dgpio = param.esp32.gpio; 13 | 14 | let rx = (dgpio.rx !== undefined ? dgpio.rx : -1); 15 | let tx = (dgpio.tx !== undefined ? dgpio.tx : -1); 16 | let cts = (dgpio.cts !== undefined ? dgpio.cts : -1); 17 | let rts = (dgpio.rts !== undefined ? dgpio.rts : -1); 18 | 19 | this._pins(uartNo, cfg, rx, tx, cts, rts); 20 | } 21 | 22 | // Set FIFO params 23 | if (param.esp32.fifo !== undefined) { 24 | let dfifo = param.esp32.fifo; 25 | 26 | let ft = (dfifo.rxFullThresh !== undefined ? dfifo.rxFullThresh : -1); 27 | let fct = (dfifo.rxFcThresh !== undefined ? dfifo.rxFcThresh : -1); 28 | let alarm = (dfifo.rxAlarm !== undefined ? dfifo.rxAlarm : -1); 29 | let et = (dfifo.txEmptyThresh !== undefined ? dfifo.txEmptyThresh : -1); 30 | 31 | this._fifo(uartNo, cfg, ft, fct, alarm, et); 32 | } 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /fs/polyfill.js: -------------------------------------------------------------------------------- 1 | // TODO: implement error & warn/debug/stack methods 2 | let console = {log: print, error: print}; 3 | let module = {exports: null, _cache: {}}; 4 | 5 | function __resolvePath(p) { 6 | let sf = '.js'; 7 | let f = p.length - 3; 8 | let e = p.indexOf(sf, f < 0 ? 0 : f); 9 | if (e === -1) { 10 | return p + sf; 11 | } 12 | 13 | return p; 14 | } 15 | 16 | function require(path) { 17 | // Add .js if not set 18 | path = __resolvePath(path); 19 | 20 | // Prevent duplicate load, return from cache 21 | let c = module._cache[path]; 22 | if (c !== undefined) { 23 | return c; 24 | } 25 | 26 | // noinspection JSUnresolvedFunction 27 | load(path); 28 | 29 | // Add module to cache 30 | c = module._cache[path] = module.exports; 31 | // clean exports data to prevent modules duplication 32 | module.exports = null; 33 | 34 | return c; 35 | } 36 | 37 | // Load Timer lib only on demand & cache result 38 | let __timer = null; 39 | 40 | function __getTimer() { 41 | if (!__timer) { 42 | // TODO: add module.export to api_timer & use require with caching 43 | // noinspection JSUnresolvedFunction 44 | load('api_timer.js'); 45 | 46 | __timer = Timer; 47 | } 48 | 49 | return __timer; 50 | } 51 | 52 | function setInterval(fn, timeout) { 53 | let t = __getTimer(); 54 | 55 | return t.set(timeout, t.REPEAT, fn, null); 56 | } 57 | 58 | function setTimeout(fn, timeout) { 59 | return __getTimer().set(timeout, 0, fn, null); 60 | } 61 | 62 | function clearTimeout(id) { 63 | return __getTimer().del(id); 64 | } 65 | 66 | function clearInterval(id) { 67 | return clearTimeout(id); 68 | } -------------------------------------------------------------------------------- /fs/api_sys.js: -------------------------------------------------------------------------------- 1 | let Sys = { 2 | // ## **`Sys._sbuf(len)`** 3 | // Helper function to allocate string of at least given length. Note that 4 | // the resulting string is usually bigger than this, and it is always 5 | // longer than 5 bytes; that's to guarantee that the string data is stored in 6 | // a common buffer and not inlined into mjs_val_t, thus the buffer can be 7 | // used as an "output" buffer: a string can be passed to some function which 8 | // will alter the contents, and these changes will be visible to the caller. 9 | _sbuf: function(len) { 10 | let chunk = ' ', buf = chunk; 11 | while (buf.length < len) buf += chunk; 12 | return buf; 13 | }, 14 | 15 | // ## **`Sys.calloc(nmemb, size)`** 16 | // Allocate a memory region. 17 | // Note: currently memory allocated this way must be explicitly released with 18 | // `free()`. 19 | malloc: ffi('void *malloc(int)'), 20 | free: ffi('void free(void *)'), 21 | 22 | // ## **`Sys.total_ram()`** 23 | // Return total available RAM in bytes. 24 | total_ram: ffi('int mgos_get_heap_size()'), 25 | 26 | // ## **`Sys.free_ram()`** 27 | // Return free available RAM in bytes. 28 | free_ram: ffi('int mgos_get_free_heap_size()'), 29 | 30 | // ## **`Sys.reboot(ms)`** 31 | // Reboot the system after `ms` milliseconds. Return value: none. 32 | reboot: ffi('void mgos_system_restart_after(int)'), 33 | 34 | // ## **`Sys.uptime()`** 35 | // Return number of seconds since last reboot. 36 | uptime: ffi('double mgos_uptime()'), 37 | 38 | // ## **`Sys.usleep(microseconds)`** 39 | // Sleep given number of microseconds. 40 | // Return value: none. 41 | usleep: ffi('void mgos_usleep(int)'), 42 | 43 | // ## **`Sys.wdt_feed()`** 44 | // Feed the watchdog timer. 45 | // Return value: none. 46 | wdt_feed: ffi('void mgos_wdt_feed()') 47 | }; 48 | -------------------------------------------------------------------------------- /fs/api_timer.js: -------------------------------------------------------------------------------- 1 | load('api_math.js'); 2 | 3 | let Timer = { 4 | _f: ffi('int mgos_strftime(char *, int, char *, int)'), 5 | 6 | // ## **`Timer.set(milliseconds, flags, handler, userdata)`** 7 | // Setup timer with `milliseconds` timeout and `handler` as a callback. 8 | // `flags` can be either 0 or `Timer.REPEAT`. In the latter case, the call 9 | // will be repeated indefinitely (but can be cancelled with `Timer.del()`), 10 | // otherwise it's a one-off. 11 | // 12 | // Return value: numeric timer ID. 13 | // 14 | // Example: 15 | // ```javascript 16 | // // Call every second 17 | // Timer.set(1000, Timer.REPEAT, function() { 18 | // let value = GPIO.toggle(2); 19 | // print(value ? 'Tick' : 'Tock'); 20 | // }, null); 21 | // ``` 22 | set: ffi('int mgos_set_timer(int,int,void(*)(userdata),userdata)'), 23 | 24 | REPEAT: 1, 25 | RUN_NOW: 2, 26 | 27 | // ## **`Timer.now()`** 28 | // Return current time as double value, UNIX epoch (seconds since 1970). 29 | now: ffi('double mg_time(void)'), 30 | 31 | // ## **`Timer.del(id)`** 32 | // Cancel previously installed timer. 33 | del: ffi('void mgos_clear_timer(int)'), 34 | 35 | // ## **`Timer.fmt(fmt, time)`** 36 | // Formats the time 'time' according to the strftime-like format 37 | // specification 'fmt'. The strftime reference can be found e.g. 38 | // [here](http://www.cplusplus.com/reference/ctime/strftime/). 39 | // Example: 40 | // ```javascript 41 | // let now = Timer.now(); 42 | // let s = Timer.fmt("Now it's %I:%M%p.", now); 43 | // print(s); // Example output: "Now it's 12:01AM." 44 | // ``` 45 | fmt: function(fmt, time) { 46 | if (!fmt) return 'invalid format'; 47 | let res = 0, t = Math.round(time || Timer.now()), s = ' '; 48 | while (res === 0) { 49 | res = this._f(s, s.length, fmt, t); 50 | if (res === -1) return 'invalid time'; 51 | if (res === 0) s += ' '; 52 | } 53 | return s.slice(0, res); 54 | }, 55 | }; 56 | -------------------------------------------------------------------------------- /fs/api_log.js: -------------------------------------------------------------------------------- 1 | let Log = { 2 | // ## **`Log.print(level, msg)`** 3 | // Print message to stderr if provided 4 | // level is >= `Cfg.get('debug.level')`. Possible levels are: 5 | // - `Log.ERROR` (0) 6 | // - `Log.WARN` (1) 7 | // - `Log.INFO` (2) 8 | // - `Log.DEBUG` (3) 9 | // - `Log.VERBOSE_DEBUG` (4) 10 | print: function(level, msg) { 11 | let mjs = getMJS(); 12 | // Frame number: we're starting from the third frame, ignoring the first 13 | // two: 14 | // - this._off() or this._fn() 15 | // - Log.print() 16 | let cfn = 2; 17 | 18 | // bcode offset of interest, and the corresponding function:lineno 19 | let offs, fn, ln; 20 | 21 | // We'll go up by call trace until we find the frame not from the current 22 | // file 23 | while (true) { 24 | offs = this._off(mjs, cfn) - 1; 25 | fn = this._fn(mjs, offs); 26 | if (fn !== "api_log.js") { 27 | // Found the first frame from other file, we're done. 28 | break; 29 | } 30 | cfn++; 31 | } 32 | ln = this._ln(mjs, offs); 33 | this._pr(fn, ln, level, msg); 34 | }, 35 | 36 | // ## **`Log.error(msg)`** 37 | // Shortcut for `Log.print(Log.ERROR, msg)` 38 | error: function(msg) { 39 | this.print(this.ERROR, msg); 40 | }, 41 | 42 | // ## **`Log.warn(msg)`** 43 | // Shortcut for `Log.print(Log.WARN, msg)` 44 | warn: function(msg) { 45 | this.print(this.WARN, msg); 46 | }, 47 | 48 | // ## **`Log.info(msg)`** 49 | // Shortcut for `Log.print(Log.INFO, msg)` 50 | info: function(msg) { 51 | this.print(this.INFO, msg); 52 | }, 53 | 54 | // ## **`Log.debug(msg)`** 55 | // Shortcut for `Log.print(Log.DEBUG, msg)` 56 | debug: function(msg) { 57 | this.print(this.DEBUG, msg); 58 | }, 59 | 60 | // ## **`Log.verboseDebug(msg)`** 61 | // Shortcut for `Log.print(Log.VERBOSE_DEBUG, msg)` 62 | verboseDebug: function(msg) { 63 | this.print(this.VERBOSE_DEBUG, msg); 64 | }, 65 | 66 | ERROR: 0, 67 | WARN: 1, 68 | INFO: 2, 69 | DEBUG: 3, 70 | VERBOSE_DEBUG: 4, 71 | 72 | _pr: ffi('void mgos_log(char *, int, int, char *)'), 73 | _fn: ffi('char *mjs_get_bcode_filename_by_offset(void *, int)'), 74 | _ln: ffi('int mjs_get_lineno_by_offset(void *, int)'), 75 | _off: ffi('int mjs_get_offset_by_call_frame_num(void *, int)'), 76 | }; 77 | -------------------------------------------------------------------------------- /fs/api_config.js: -------------------------------------------------------------------------------- 1 | let Cfg = { 2 | _get: ffi('void *mgos_mjs_get_config()'), 3 | _set: ffi('bool mgos_config_apply(char *, bool)'), 4 | _desc: ffi('void *mgos_config_schema()'), 5 | _find: ffi('void *mgos_conf_find_schema_entry(char *, void *)'), 6 | _type: ffi('int mgos_conf_value_type(void *)'), 7 | _str: ffi('char *mgos_conf_value_string_nonnull(void *, void *)'), 8 | _int: ffi('int mgos_conf_value_int(void *, void *)'), 9 | _dbl: ffi('double mgos_conf_value_double(void *, void *)'), 10 | _INT: 0, 11 | _BOOL: 1, 12 | _DBL: 2, 13 | _STR: 3, 14 | _OBJ: 4, 15 | 16 | // ## **`Cfg.get(path)`** 17 | // Get the config value by the configuration variable. Currently, only 18 | // simple types are returned: strings, ints, booleans, doubles. Objects 19 | // are not yet supported. 20 | // 21 | // Examples: 22 | // ```javascript 23 | // load('api_config.js'); 24 | // Cfg.get('device.id'); // returns a string 25 | // Cfg.get('debug.level'); // returns an integer 26 | // Cfg.get('wifi.sta.enable'); // returns a boolean 27 | // ``` 28 | get: function(path) { 29 | let entry = this._find(path, this._desc()); 30 | if (entry === null) return undefined; 31 | let type = this._type(entry); 32 | let cfg = this._get(); 33 | if (type === this._STR) { 34 | return this._str(cfg, entry); 35 | } else if (type === this._INT) { 36 | return this._int(cfg, entry); 37 | } else if (type === this._DBL) { 38 | return this._dbl(cfg, entry); 39 | } else if (type === this._BOOL) { 40 | return (this._int(cfg, entry) !== 0); 41 | } else if (type === this._OBJ) { 42 | /* TODO */ 43 | return undefined; 44 | } else { 45 | /* TODO: an error */ 46 | return undefined; 47 | } 48 | }, 49 | 50 | // ## **`Cfg.set(obj, opt_save)`** 51 | // Set the configuration. `obj` must be a subset of the whole configuation 52 | // tree. `save` is boolean flag that indicating whether the change should 53 | // be saved - it could be omitted, in which case it defaults to `true`. 54 | // Examples: 55 | // ```javascript 56 | // load('api_config.js'); 57 | // Cfg.set({wifi: {ap: {enable: false}}}); // Disable WiFi AP mode 58 | // Cfg.set({debug: {level: 3}}); // Set debug level to 3 59 | // ``` 60 | set: function(obj, save) { 61 | return this._set(JSON.stringify(obj), save === undefined ? true : save); 62 | }, 63 | }; 64 | -------------------------------------------------------------------------------- /src/mos_mjs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2018 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the ""License""); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an ""AS IS"" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include "mos_mjs.h" 19 | 20 | #include "common/cs_dbg.h" 21 | #include "common/platform.h" 22 | 23 | #include "mgos_app.h" 24 | #include "mgos_dlsym.h" 25 | #include "mgos_event.h" 26 | #include "mgos_hal.h" 27 | #include "mgos_mongoose.h" 28 | #include "mgos_net.h" 29 | #include "mgos_sys_config.h" 30 | #ifdef MGOS_HAVE_WIFI 31 | #include "mgos_wifi.h" 32 | #endif 33 | 34 | struct mjs *mjs = NULL; 35 | 36 | static void run_if_exists(const char *fname) { 37 | struct stat st; 38 | if (stat(fname, &st) != 0) return; 39 | LOG(LL_DEBUG, ("Trying to run %s...", fname)); 40 | if (mjs_exec_file(mjs, fname, NULL) != MJS_OK) { 41 | mjs_print_error(mjs, stderr, NULL, 1 /* print_stack_trace */); 42 | } 43 | } 44 | 45 | /* 46 | * Runs when all initialization (all libs + app) is done 47 | * Execute two files: 48 | * - init.js, which is supposed to be included in the firmware and thus 49 | * overridden by the OTA 50 | * - app.js, which is NOT supposed to be included in the FW and thus 51 | * it survives OTA. 52 | * For example, if you want to customize demo-js built-in firmware by your 53 | * own custom code that survives OTA, upload your own app.js to the device. 54 | * Then you can update the device and app.js will be preserved. 55 | */ 56 | static void s_init_done_handler(int ev, void *ev_data, void *userdata) { 57 | int mem1, mem2; 58 | 59 | mem1 = mgos_get_free_heap_size(); 60 | run_if_exists("init.js"); 61 | run_if_exists("app.js"); 62 | mem2 = mgos_get_free_heap_size(); 63 | LOG(LL_DEBUG, ("mJS RAM stat: before user code: %d after: %d", mem1, mem2)); 64 | 65 | (void) ev; 66 | (void) ev_data; 67 | (void) userdata; 68 | } 69 | 70 | struct cb_info { 71 | void (*cb)(enum mgos_net_event ev, void *arg); 72 | void *arg; 73 | }; 74 | 75 | bool mgos_mjs_init(void) { 76 | /* Initialize JavaScript engine */ 77 | int mem1, mem2; 78 | mem1 = mgos_get_free_heap_size(); 79 | mjs = mjs_create(); 80 | mem2 = mgos_get_free_heap_size(); 81 | mjs_set_ffi_resolver(mjs, mgos_dlsym); 82 | mjs_set_generate_jsc(mjs, mgos_sys_config_get_mjs_generate_jsc()); 83 | 84 | #ifdef MGOS_HAVE_WIFI 85 | { 86 | mjs_val_t global_obj = mjs_get_global(mjs); 87 | mjs_val_t wifi_obj = mjs_mk_object(mjs); 88 | mjs_set(mjs, global_obj, "Wifi", ~0, wifi_obj); 89 | mjs_set(mjs, wifi_obj, "scan", ~0, mjs_mk_foreign(mjs, mgos_wifi_scan_js)); 90 | } 91 | #endif 92 | 93 | /* 94 | * We also need to run init.js, but we can't do that here because init.js 95 | * might depend on some other libs which weren't initialized yet. Thus we use 96 | * the INIT_DONE event. 97 | */ 98 | mgos_event_add_handler(MGOS_EVENT_INIT_DONE, s_init_done_handler, NULL); 99 | 100 | LOG(LL_DEBUG, 101 | ("mJS memory stat: before init: %d after init: %d", mem1, mem2)); 102 | return true; 103 | } 104 | 105 | struct mgos_config *mgos_mjs_get_config(void) { 106 | return &mgos_sys_config; 107 | } 108 | 109 | struct mjs *mgos_mjs_get_global(void) { 110 | return mjs; 111 | } 112 | -------------------------------------------------------------------------------- /fs/api_gpio.js: -------------------------------------------------------------------------------- 1 | let GPIO = { 2 | // ## **`GPIO.set_mode(pin, mode)`** 3 | // Set GPIO pin mode. 4 | // `mode` can be either `GPIO.MODE_INPUT` or `GPIO.MODE_OUTPUT`. 5 | set_mode: ffi('int mgos_gpio_set_mode(int,int)'), 6 | MODE_INPUT: 0, 7 | MODE_OUTPUT: 1, 8 | 9 | // ## **`GPIO.set_pull(pin, pull_type)`** 10 | // Set GPIO pin pull type. 11 | // `pull_type` can be either `GPIO.PULL_NONE`, `GPIO.PULL_UP`, or `GPIO.PULL_DOWN`. 12 | set_pull: ffi('int mgos_gpio_set_pull(int,int)'), 13 | PULL_NONE: 0, 14 | PULL_UP: 1, 15 | PULL_DOWN: 2, 16 | 17 | // ## **`GPIO.setup_input(pin, pull_type)`** 18 | // Setup pin as input and configure pull type. 19 | // `pull_type` can be either `GPIO.PULL_NONE`, `GPIO.PULL_UP`, or `GPIO.PULL_DOWN`. 20 | setup_input: ffi('int mgos_gpio_setup_input(int,int)'), 21 | 22 | // ## **`GPIO.setup_output(pin, level)`** 23 | // Setup pin as output and set initial level, 0 or 1. 24 | // Avoids spurious transitions: applies level first, then sets mode. 25 | setup_output: ffi('int mgos_gpio_setup_output(int,int)'), 26 | 27 | // ## **`GPIO.toggle(pin)`** 28 | // Toggle the level of certain GPIO pin. 29 | // Return value: 0 or 1, indicating the resulting pin level. 30 | toggle: ffi('int mgos_gpio_toggle(int)'), 31 | 32 | // ## **`GPIO.write(pin, level)`** 33 | // Set GPIO pin level to either 0 or 1. Return value: none. 34 | write: ffi('void mgos_gpio_write(int,int)'), 35 | 36 | // ## **`GPIO.read(pin)`** 37 | // Read GPIO pin level. Return value: 0 or 1. 38 | read: ffi('int mgos_gpio_read(int)'), 39 | 40 | // ## **`GPIO.read(pin)`** 41 | // Read GPIO pin level for GPIO in OUTPUT state. Return value: 0 or 1. 42 | read_out: ffi ('int mgos_gpio_read_out(int)'), 43 | 44 | // ## **`GPIO.enable_int(pin)`** 45 | // Enable interrupts on GPIO pin. 46 | // This function must be called AFTER the interrupt handler is installed. 47 | // Return value: 1 in case of success, 0 otherwise. 48 | enable_int: ffi('int mgos_gpio_enable_int(int)'), 49 | 50 | // ## **`GPIO.disable_int(pin)`** 51 | // Disable interrupts on GPIO pin. 52 | // Return value: 1 in case of success, 0 otherwise. 53 | disable_int: ffi('int mgos_gpio_disable_int(int)'), 54 | 55 | // ## **`GPIO.blink(pin, on_ms, off_ms)`** 56 | // A utility function that takes care of blinking an LED. 57 | // The pin must be configured as output first. 58 | // On (output "1") and off ("0") times are specified in milliseconds. 59 | // Set to (0, 0) to disable. 60 | // Return value: 1 on success, 0 on failure. 61 | blink: ffi('int mgos_gpio_blink(int, int, int)'), 62 | 63 | // ## **`GPIO.set_int_handler(pin, mode, handler)`** 64 | // Install GPIO interrupt handler. `mode` could be one of: `GPIO.INT_NONE`, 65 | // `GPIO.INT_EDGE_POS`, `GPIO.INT_EDGE_NEG`, `GPIO.INT_EDGE_ANY`, 66 | // `GPIO.INT_LEVEL_HI`, `GPIO.INT_LEVEL_LO`. 67 | // Return value: 1 in case of success, 0 otherwise. 68 | // Example: 69 | // ```javascript 70 | // GPIO.set_mode(pin, GPIO.MODE_INPUT); 71 | // GPIO.set_int_handler(pin, GPIO.INT_EDGE_NEG, function(pin) { 72 | // print('Pin', pin, 'got interrupt'); 73 | // }, null); 74 | // GPIO.enable_int(pin); 75 | // ``` 76 | set_int_handler: ffi('int mgos_gpio_set_int_handler(int,int,void(*)(int,userdata),userdata)'), 77 | INT_NONE: 0, 78 | INT_EDGE_POS: 1, 79 | INT_EDGE_NEG: 2, 80 | INT_EDGE_ANY: 3, 81 | INT_LEVEL_HI: 4, 82 | INT_LEVEL_LO: 5, 83 | 84 | // ## **`GPIO.set_button_handler(pin, pull, intmode, period, handler)`** 85 | // Install 86 | // GPIO button handler. `pull` is pull type, `intmode` is interrupt mode, 87 | // `period` is debounce interval in milliseconds, handler is a function that 88 | // receives pin number. 89 | // Return value: 1 in case of success, 0 otherwise. 90 | // Example: 91 | // ```javascript 92 | // GPIO.set_button_handler(pin, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 200, function(x) { 93 | // print('Button press, pin: ', x); 94 | // }, null); 95 | // ``` 96 | set_button_handler: ffi('int mgos_gpio_set_button_handler(int,int,int,int,void(*)(int, userdata), userdata)'), 97 | }; 98 | -------------------------------------------------------------------------------- /fs/api_http.js: -------------------------------------------------------------------------------- 1 | load('api_net.js'); 2 | 3 | let URL = { 4 | // ## **`URL.parse(url)`** 5 | // Parse URL string, return and object with `ssl`, `addr`, `uri` keys. 6 | // 7 | // Example: 8 | // ```javascript 9 | // print(JSON.stringify(URL.parse('https://a.b:1234/foo?bar'))); 10 | // // Prints: {"uri":"/foo?bar","addr":"a.b:1234","ssl":true} 11 | // ``` 12 | parse: function(url) { 13 | let ssl = false, addr, port = '80', uri = '/', app = true; 14 | if (url.slice(0, 8) === 'https://') { 15 | port = '443'; 16 | ssl = true; 17 | url = url.slice(8); 18 | } 19 | if (url.slice(0, 7) === 'http://') { 20 | url = url.slice(7); 21 | } 22 | addr = url; 23 | for (let i = 0; i < url.length; i++) { 24 | let ch = url[i]; 25 | if (ch === ':') app = false; 26 | if (ch === '/') { 27 | addr = url.slice(0, i); 28 | uri = url.slice(i); 29 | break; 30 | } 31 | } 32 | if (app) addr += ':' + port; 33 | return {ssl: ssl, addr: addr, uri: uri}; 34 | }, 35 | }; 36 | 37 | let HTTP = { 38 | _getm: ffi('void *mgos_get_msg_ptr(void *)'), 39 | _getb: ffi('void *mgos_get_body_ptr(void *)'), 40 | _mgp: ffi('void *mgos_get_mgstr_ptr(void *)'), 41 | _mgl: ffi('int mgos_get_mgstr_len(void *)'), 42 | 43 | _c: ffi('void *mgos_connect_http(char *, void (*)(void *, int, void *, userdata), userdata)'), 44 | _cs: ffi('void *mgos_connect_http_ssl(char *, void (*)(void *, int, void *, userdata), userdata, char *, char *, char *)'), 45 | _sp: ffi('void mg_set_protocol_http_websocket(void *)'), 46 | 47 | _mstr: function(hmptr, func) { 48 | let mgstr = func(hmptr); 49 | return mkstr(this._mgp(mgstr), this._mgl(mgstr)); 50 | }, 51 | 52 | // ## **`HTTP.query(options);`** 53 | // Send HTTP request. Options object accepts the following fields: 54 | // `url` - mandatory URL to fetch, `success` - optional callback function 55 | // that receives reply body, `error` - optional error callback that receives 56 | // error string, `data` - optional object with request parameters. 57 | // By default, `GET` method is used. If `data` is specified, POST method 58 | // is used, the `data` object gets `JSON.stringify()`-ed and used as a 59 | // HTTP message body. 60 | // 61 | // In order to send HTTPS request, use `https://...` URL. Note that in that 62 | // case `ca.pem` file must contain CA certificate of the requested server. 63 | // 64 | // Example: 65 | // ```javascript 66 | // HTTP.query({ 67 | // url: 'http://httpbin.org/post', 68 | // headers: { 'X-Foo': 'bar' }, // Optional - headers 69 | // data: {foo: 1, bar: 'baz'}, // Optional. If set, JSON-encoded and POST-ed 70 | // success: function(body, full_http_msg) { print(body); }, 71 | // error: function(err) { print(err); }, // Optional 72 | // }); 73 | // ``` 74 | query: function(opts) { 75 | let url = URL.parse(opts.url || ''); 76 | return Net.connect({ 77 | addr: url.addr, 78 | ssl: url.ssl, 79 | u: url, 80 | opts: opts, 81 | onconnect: function(conn, edata, ud) { 82 | let opts = ud.opts; 83 | let body = opts.data || ''; 84 | if (typeof(body) !== 'string') body = JSON.stringify(body); 85 | let meth = body ? 'POST' : 'GET'; 86 | let host = 'Host: ' + ud.u.addr + '\r\n'; 87 | let cl = 'Content-Length: ' + JSON.stringify(body.length) + '\r\n'; 88 | let hdrs = opts.headers || {}; 89 | for (let k in hdrs) { 90 | cl += k + ': ' + hdrs[k] + '\r\n'; 91 | } 92 | let req = meth + ' ' + ud.u.uri + ' HTTP/1.0\r\n' + host + cl + '\r\n'; 93 | Net.send(conn, req); 94 | Net.send(conn, body); 95 | HTTP._sp(conn); 96 | }, 97 | onevent: function(conn, buf, ev, edata, ud) { 98 | if (ev === 101 && ud.opts.success) { 99 | let body = HTTP._mstr(edata, HTTP._getb); 100 | let full = HTTP._mstr(edata, HTTP._getm); 101 | ud.opts.success(body, full); 102 | ud.ok = true; 103 | } 104 | }, 105 | onclose: function(conn, ud) { 106 | let opts = ud.opts; 107 | if (!ud.ok && opts.error) opts.error('', 'Request failed', opts); 108 | }, 109 | }); 110 | }, 111 | }; 112 | -------------------------------------------------------------------------------- /fs/api_events.js: -------------------------------------------------------------------------------- 1 | let Event = { 2 | // ## **`Event.addHandler(ev, callback, userdata)`** 3 | // Add a handler for the given event `ev`. Callback should look like: 4 | // 5 | // function(ev, evdata, userdata) { /* ... */ } 6 | // 7 | // Example: 8 | // ```javascript 9 | // 10 | // Event.addHandler(Event.REBOOT, function(ev, evdata, ud) { 11 | // print("Going to reboot!"); 12 | // }, null); 13 | // ``` 14 | addHandler: ffi( 15 | 'bool mgos_event_add_handler(int, void(*)(int, void *, userdata), userdata)'), 16 | 17 | // ## **`Event.addGroupHandler(evgrp, callback, userdata)`** 18 | // Like `Event.addHandler()`, but subscribes on all events in the given 19 | // event group `evgrp`. Event group includes all events from `evgrp & ~0xff` 20 | // to `evgrp | 0xff`. 21 | // 22 | // Example: 23 | // ```javascript 24 | // 25 | // Event.addGroupHandler(Event.SYS, function(ev, evdata, ud) { 26 | // print("Sys event:", ev); 27 | // }, null); 28 | // ``` 29 | addGroupHandler: ffi( 30 | 'bool mgos_event_add_group_handler(int, void(*)(int, void *, userdata), userdata)'), 31 | 32 | // ## **`Event.on(event_num, callback, userdata)`** 33 | // Alias for Event.addHandler 34 | on: function(ev, cb, cbdata) { 35 | this.addHandler(ev, cb, cbdata); 36 | return this; 37 | }, 38 | 39 | // ## **`Event.regBase(base_event_number, name)`** 40 | // Register a base event number in order to prevent event number conflicts. 41 | // Use `Event.baseNumber(id)` to get `base_event_number`; `name` is an 42 | // arbitrary event name. 43 | // 44 | // Example: 45 | // ```javascript 46 | // let bn = Event.baseNumber("ABC"); 47 | // if (!Event.regBase(bn, "My module")) { 48 | // die("Failed to register base event number"); 49 | // } 50 | // 51 | // let MY_EVENT_FOO = bn + 0; 52 | // let MY_EVENT_BAR = bn + 1; 53 | // let MY_EVENT_BAZ = bn + 2; 54 | // ``` 55 | regBase: ffi('bool mgos_event_register_base(int, char *)'), 56 | 57 | // ## **`Event.baseNumber(id)`** 58 | // Generates unique base event number (32-bit) by a 3-char string. 59 | // LSB is always zero, and a library can use it to create up to 256 unique 60 | // events. 61 | // 62 | // A library should call `Event.regBase()` in order to claim 63 | // it and prevent event number conflicts. (see example there) 64 | baseNumber: function(id) { 65 | if (id.length !== 3) { 66 | die('Base event id should have exactly 3 chars'); 67 | return -1; 68 | } 69 | 70 | return (id.at(0) << 24) | (id.at(1) << 16) | (id.at(2) << 8); 71 | }, 72 | 73 | // ## **`Event.trigger(ev, evdata)`** 74 | // Trigger an event with the given id `ev` and event data `evdata`. 75 | trigger: ffi('int mgos_event_trigger(int, void *)'), 76 | 77 | // ## **`Event.evdataLogStr(evdata)`** 78 | // Getter function for the `evdata` given to the event callback for the event 79 | // `Event.LOG`, see `Event.addHandler()`. 80 | evdataLogStr: function(evdata) { 81 | return mkstr(Event._gdd(evdata), 0, Event._gdl(evdata), true); 82 | }, 83 | 84 | _gdd: ffi('void *mgos_debug_event_get_ptr(void *)'), 85 | _gdl: ffi('int mgos_debug_event_get_len(void *)'), 86 | }; 87 | 88 | Event.SYS = Event.baseNumber('MOS'); 89 | 90 | // NOTE: INIT_DONE is unavailable here because init.js is executed in 91 | // INIT_DONE hook 92 | 93 | // ## **`Event.LOG`** 94 | // System event which is triggered every time something is printed to the 95 | // log. In the callback, use `Event.evdataLogStr(evdata)` to get string 96 | // which was printed. 97 | Event.LOG = Event.SYS + 1; 98 | 99 | // ## **`Event.REBOOT`** 100 | // System event which is triggered right before going to reboot. `evdata` 101 | // is irrelevant for this event. 102 | Event.REBOOT = Event.SYS + 2; 103 | 104 | // ## **`Event.OTA_STATUS`** 105 | // System event which is triggered when OTA status changes. 106 | // 107 | // In the callback, use `OTA.evdataOtaStatusMsg(evdata)` from `api_ota.js` to 108 | // get the OTA status message. 109 | Event.OTA_TIME_CHANGED = Event.SYS + 3; 110 | 111 | // ## **`Event.CLOUD_CONNECTED`** 112 | // Triggered when device is connected to the cloud (mqtt, dash) 113 | Event.CLOUD_CONNECTED = Event.SYS + 4; 114 | 115 | // ## **`Event.CLOUD_DISCONNECTED`** 116 | // Triggered when device is disconnected from the cloud 117 | Event.CLOUD_DISCONNECTED = Event.SYS + 5; 118 | -------------------------------------------------------------------------------- /fs/api_net.js: -------------------------------------------------------------------------------- 1 | load('api_events.js'); 2 | 3 | let Net = { 4 | _rb: ffi('void *mgos_get_recv_mbuf(void *)'), 5 | _mptr: ffi('void *mgos_get_mbuf_ptr(void *)'), 6 | _glen: ffi('int mgos_get_mbuf_len(void *)'), 7 | _mrem: ffi('void mbuf_remove(void *, int)'), 8 | _isin: ffi('bool mgos_is_inbound(void *)'), 9 | 10 | _bind: ffi('void *mgos_bind(char *, void (*)(void *, int, void *, userdata), userdata)'), 11 | _c: ffi('void *mgos_connect(char *, void (*)(void *, int, void *, userdata), userdata)'), 12 | _cs: ffi('void *mgos_connect_ssl(char *, void (*)(void *, int, void *, userdata), userdata, char *, char *, char *)'), 13 | _send: ffi('void mg_send(void *, void *, int)'), 14 | _ctos: ffi('int mg_conn_addr_to_str(void *, char *, int, int)'), 15 | 16 | // Return string contained in connection's recv_mbuf 17 | _rbuf: function(conn) { 18 | let rb = this._rb(conn); 19 | return mkstr(this._mptr(rb), this._glen(rb)); 20 | }, 21 | 22 | // **`Net.ctos(conn, local, ip, port)`** 23 | // Convert address of a connection `conn` to string. Set `local` to 24 | // `true` to stringify local address, otherwise `false` to stringify remote. 25 | // Set `ip` to `true` to stringify IP, `port` to stringify port. Example: 26 | // ```javascript 27 | // print('Connection from:', Net.ctos(conn, false, true, true)); 28 | // ``` 29 | ctos: function(conn, local, ip, port) { 30 | let buf = ' '; 31 | let flags = (local ? 0 : 4) | (ip ? 1 : 0) | (port ? 2 : 0); 32 | let n = this._ctos(conn, buf, buf.length, flags); 33 | return buf.slice(0, n); 34 | }, 35 | 36 | // **`Net.discard(conn, len)`** 37 | // Remove initial `len` bytes of data from the connection's `conn` 38 | // receive buffer in order to discard that data and reclaim RAM to the system. 39 | discard: function(conn, len) { 40 | this._mrem(this._rb(conn), len); 41 | }, 42 | 43 | // Event handler. Expects an object with connect/data/close/event user funcs. 44 | _evh: function(conn, ev, edata, obj) { 45 | if (ev === 0) return; 46 | 47 | if (ev === 1 || ev === 2) { 48 | if (obj.onconnect) obj.onconnect(conn, edata, obj); 49 | } else if (ev === 3) { 50 | if (obj.ondata) obj.ondata(conn, Net._rbuf(conn), obj); 51 | } else if (ev === 5) { 52 | if (obj.onclose) obj.onclose(conn, obj); 53 | let inb = Net._isin(conn); // Is this an inbound connection ? 54 | if (!inb) ffi_cb_free(Net._evh, obj); 55 | } else if (ev >= 6) { 56 | if (obj.onevent) obj.onevent(conn, Net._rbuf(conn), ev, edata, obj); 57 | } 58 | }, 59 | 60 | // ## **`Net.serve(options)`** 61 | // Start TCP or UDP server. `options` is an object: 62 | // ```javascript 63 | // { 64 | // // Required. Port to listen on, 'tcp://PORT' or `udp://PORT`. 65 | // addr: 'tcp://1234', 66 | // // Optional. Called when connection is established. 67 | // onconnect: function(conn) {}, 68 | // // Optional. Called when new data is arrived. 69 | // ondata: function(conn, data) {}, 70 | // // Optional. Called when protocol-specific event is triggered. 71 | // onevent: function(conn, data, ev, edata) {}, 72 | // // Optional. Called when the connection is about to close. 73 | // onclose: function(conn) {}, 74 | // // Optional. Called when on connection error. 75 | // onerror: function(conn) {}, 76 | // } 77 | // ``` 78 | // Example - a UDP echo server. Change `udp://` to `tcp://` to turn this 79 | // example into the TCP echo server: 80 | // ```javascript 81 | // Net.serve({ 82 | // addr: 'udp://1234', 83 | // ondata: function(conn, data) { 84 | // print('Received from:', Net.ctos(conn, false, true, true), ':', data); 85 | // Net.send(conn, data); // Echo received data back 86 | // Net.discard(conn, data.length); // Discard received data 87 | // }, 88 | // }); 89 | // ``` 90 | serve: function(obj) { 91 | return this._bind(obj.addr, this._evh, obj); 92 | }, 93 | 94 | // ## **`Net.connect(options)`** 95 | // Connect to a remote host. `options` is the same as for the `Net.serve`. 96 | // The addr format is `[PROTO://]HOST:PORT`. `PROTO` could be `tcp` or 97 | // `udp`. `HOST` could be an IP address or a host name. If `HOST` is a name, 98 | // it will be resolved asynchronously. 99 | // 100 | // Examples of valid addresses: `google.com:80`, `udp://1.2.3.4:53`, 101 | // `10.0.0.1:443`, `[::1]:80`. 102 | connect: function(obj) { 103 | if (obj.ssl) { 104 | return this._cs(obj.addr, this._evh, obj, obj.cert || '', obj.key || '', obj.ca_cert || 'ca.pem'); 105 | } else { 106 | return this._c(obj.addr, this._evh, obj); 107 | } 108 | }, 109 | 110 | // ## **`Net.close(conn)`** 111 | // Send all pending data to the remote peer, 112 | // and disconnect when all data is sent. 113 | // Return value: none. 114 | close: ffi('void mgos_disconnect(void *)'), 115 | 116 | // ## **`Net.send(conn, data)`** 117 | // Send data to the remote peer. `data` is an mJS string. 118 | // Return value: none. 119 | send: function(c, msg) { 120 | return Net._send(c, msg, msg.length); 121 | }, 122 | 123 | // ## **`Net.EVENT_GRP`** 124 | // Net events group, to be used with `Event.addGroupHandler()`. Possible 125 | // events are: 126 | // - `Net.STATUS_DISCONNECTED` 127 | // - `Net.STATUS_CONNECTING` 128 | // - `Net.STATUS_CONNECTED` 129 | // - `Net.STATUS_GOT_IP` 130 | EVENT_GRP: Event.baseNumber("NET"), 131 | }; 132 | 133 | Net.STATUS_DISCONNECTED = Net.EVENT_GRP + 0; 134 | Net.STATUS_CONNECTING = Net.EVENT_GRP + 1; 135 | Net.STATUS_CONNECTED = Net.EVENT_GRP + 2; 136 | Net.STATUS_GOT_IP = Net.EVENT_GRP + 3; 137 | -------------------------------------------------------------------------------- /fs/api_uart.js: -------------------------------------------------------------------------------- 1 | // UART API. Source C API is defined at: 2 | // [mgos_uart.h](https://github.com/cesanta/mongoose-os/blob/master/fw/src/mgos_uart.h) 3 | let UART = { 4 | _free: ffi('void free(void *)'), 5 | _cdef: ffi('void *mgos_uart_config_get_default(int)'), 6 | _cbp: ffi('void mgos_uart_config_set_basic_params(void *, int, int, int, int)'), 7 | _crx: ffi('void mgos_uart_config_set_rx_params(void *, int, int, int)'), 8 | _ctx: ffi('void mgos_uart_config_set_tx_params(void *, int, int)'), 9 | _cfg: ffi('int mgos_uart_configure(int, void *)'), 10 | _wr: ffi('int mgos_uart_write(int, char *, int)'), 11 | _rd: ffi('int mgos_uart_read(int, void *, int)'), 12 | 13 | // ## **`UART.setConfig(uartNo, param)`** 14 | // Set UART config. `param` is an 15 | // object with the following optional fields: 16 | // 17 | // - `baudRate`: baud rate, integer, default: 115200; 18 | // - `numDataBits`: Number of data bits, default: 8; 19 | // - `parity`: Parity: 0 - none, 1 - even, 2 - odd; default: none; 20 | // - `numStopBits`: Number of stop bits: 1 - 1 bit, 2 - 2 bits, 3 - 1.5; default: 1; 21 | // - `rxBufSize`: size of the Rx buffer, integer, default: 256; 22 | // - `rxFlowControl`: whether Rx flow control (RTS pin) is enabled, boolean, 23 | // default: false; 24 | // - `rxLingerMicros`: how many microseconds to linger after Rx fifo 25 | // is empty, in case more data arrives. Integer, default: 15; 26 | // - `txBufSize`: size of the Tx buffer, integer, default: 256; 27 | // - `txFlowControl`: whether Tx flow control (CTS pin) is enabled, boolean, 28 | // default: false; 29 | // 30 | // Other than that, there are architecture-dependent settings, grouped in 31 | // the objects named with the architecture name: "esp32", "esp8266", etc. 32 | // 33 | // Settings for esp32: 34 | // 35 | // ``` 36 | // esp32: { 37 | // /* 38 | // * GPIO pin numbers, default values depend on UART. 39 | // * 40 | // * UART 0: Rx: 3, Tx: 1, CTS: 19, RTS: 22 41 | // * UART 1: Rx: 13, Tx: 14, CTS: 15, RTS: 16 42 | // * UART 2: Rx: 17, Tx: 25, CTS: 26, RTS: 27 43 | // */ 44 | // gpio: { 45 | // rx: number, 46 | // tx: number, 47 | // cts: number, 48 | // rts: number, 49 | // }, 50 | // 51 | // /* Hardware FIFO tweaks */ 52 | // fifo: { 53 | // /* 54 | // * A number of bytes in the hardware Rx fifo, should be between 1 and 127. 55 | // * How full hardware Rx fifo should be before "rx fifo full" interrupt is 56 | // * fired. 57 | // */ 58 | // rxFullThresh: number, 59 | // 60 | // /* 61 | // * A number of bytes in the hardware Rx fifo, should be more than 62 | // * rx_fifo_full_thresh. 63 | // * 64 | // * How full hardware Rx fifo should be before CTS is deasserted, telling 65 | // * the other side to stop sending data. 66 | // */ 67 | // rxFcThresh: number, 68 | // 69 | // /* 70 | // * Time in uart bit intervals when "rx fifo full" interrupt fires even if 71 | // * it's not full enough 72 | // */ 73 | // rxAlarm: number, 74 | // 75 | // /* 76 | // * A number of bytes in the hardware Tx fifo, should be between 1 and 127. 77 | // * When the number of bytes in Tx buffer becomes less than 78 | // * tx_fifo_empty_thresh, "tx fifo empty" interrupt fires. 79 | // */ 80 | // txEmptyThresh: number, 81 | // }, 82 | // } 83 | // ``` 84 | setConfig: function(uartNo, param) { 85 | let cfg = this._cdef(uartNo); 86 | 87 | this._cbp(cfg, param.baudRate || 115200, 88 | param.numDataBits || 8, 89 | param.parity || 0, 90 | param.numStopBits || 1); 91 | 92 | this._crx( 93 | cfg, 94 | param.rxBufSize || 256, 95 | param.rxFlowControl || false, 96 | param.rxLingerMicros || 15 97 | ); 98 | 99 | this._ctx( 100 | cfg, 101 | param.txBufSize || 256, 102 | param.txFlowControl || false 103 | ); 104 | 105 | // Apply arch-specific config 106 | if (this._arch !== undefined) { 107 | this._arch.scfg(uartNo, cfg, param); 108 | } 109 | 110 | let res = this._cfg(uartNo, cfg); 111 | 112 | this._free(cfg); 113 | cfg = null; 114 | 115 | return res; 116 | }, 117 | 118 | // ## **`UART.setDispatcher(uartNo, callback, userdata)`** 119 | // Set UART dispatcher 120 | // callback which gets invoked when there is a new data in the input buffer 121 | // or when the space becomes available on the output buffer. 122 | // 123 | // Callback receives the following arguments: `(uartNo, userdata)`. 124 | setDispatcher: ffi('void mgos_uart_set_dispatcher(int, void(*)(int, userdata), userdata)'), 125 | 126 | // ## **`UART.write(uartNo, data)`** 127 | // Write data to the buffer. Returns number of bytes written. 128 | // 129 | // Example usage: `UART.write(1, "foobar")`, in this case, 6 bytes will be written. 130 | write: function(uartNo, data) { 131 | this._wr(uartNo, data, data.length); 132 | }, 133 | 134 | // ## **`UART.writeAvail(uartNo)`** 135 | // Return amount of space available in the output buffer. 136 | writeAvail: ffi('int mgos_uart_write_avail(int)'), 137 | 138 | // ## **`UART.read(uartNo)`** 139 | // It never blocks, and returns a string containing 140 | // read data (which will be empty if there's no data available). 141 | read: function(uartNo) { 142 | let n = 0; let res = ''; let buf = 'xxxxxxxxxx'; // Should be > 5 143 | while ((n = this._rd(uartNo, buf, buf.length)) > 0) { 144 | res += buf.slice(0, n); 145 | } 146 | return res; 147 | }, 148 | // ## **`UART.readAvail(uartNo)`** 149 | // Return amount of data available in the input buffer. 150 | readAvail: ffi('int mgos_uart_read_avail(int)'), 151 | 152 | // ## **`UART.setRxEnabled(uartNo)`** 153 | // Set whether Rx is enabled. 154 | setRxEnabled: ffi('void mgos_uart_set_rx_enabled(int, int)'), 155 | // ## **`UART.isRxEnabled(uartNo)`** 156 | // Returns whether Rx is enabled. 157 | isRxEnabled: ffi('int mgos_uart_is_rx_enabled(int)'), 158 | 159 | // ## **`UART.flush(uartNo)`** 160 | // Flush the UART output buffer, wait for the data to be sent. 161 | flush: ffi('void mgos_uart_flush(int)'), 162 | }; 163 | 164 | // Load arch-specific API 165 | load('api_arch_uart.js'); 166 | --------------------------------------------------------------------------------