Initial commit
This commit is contained in:
22
build/fs/api_adc.js
Normal file
22
build/fs/api_adc.js
Normal file
@@ -0,0 +1,22 @@
|
||||
let ADC = {
|
||||
// ## **`ADC.enable(pin)`**
|
||||
// Configure and enable ADC for a `pin`,
|
||||
// return 1 if success, 0 otherwise.
|
||||
enable: ffi('int mgos_adc_enable(int)'),
|
||||
// ## **`ADC.read(pin)`**
|
||||
// Read `pin` analog value, return an integer.
|
||||
//
|
||||
// Note for ESP8266 platform:
|
||||
// with this function, you can also measure the power voltage
|
||||
// of VDD33 pin 3 and 4. Then:
|
||||
// 1) TOUT pin has to be floating in the circuit
|
||||
// (not connected to anything);
|
||||
// 2) In mos.yaml must be set this feature:
|
||||
// build_vars:
|
||||
// MGOS_ADC_MODE_VDD: 1
|
||||
// 3) The return value may be different in different Wi-Fi modes,
|
||||
// for example, in Modem-sleep mode or in normal Wi-Fi working
|
||||
// mode.
|
||||
// Return value: Power voltage of VDD33; unit: 1/1024 V.
|
||||
read: ffi('int mgos_adc_read(int)'),
|
||||
};
|
34
build/fs/api_arch_uart.js
Normal file
34
build/fs/api_arch_uart.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// esp32 architecture-dependent UART wrappers
|
||||
UART._arch = {
|
||||
_pins: ffi('void esp32_uart_config_set_pins(int, void *, int, int, int, int)'),
|
||||
_fifo: ffi('void esp32_uart_config_set_fifo(int, void *, int, int, int, int)'),
|
||||
|
||||
// Set arch-dependent UART config
|
||||
scfg: function(uartNo, cfg, param) {
|
||||
if (param.esp32 === undefined) return;
|
||||
|
||||
// Set GPIO params
|
||||
if (param.esp32.gpio !== undefined) {
|
||||
let dgpio = param.esp32.gpio;
|
||||
|
||||
let rx = (dgpio.rx !== undefined ? dgpio.rx : -1);
|
||||
let tx = (dgpio.tx !== undefined ? dgpio.tx : -1);
|
||||
let cts = (dgpio.cts !== undefined ? dgpio.cts : -1);
|
||||
let rts = (dgpio.rts !== undefined ? dgpio.rts : -1);
|
||||
|
||||
this._pins(uartNo, cfg, rx, tx, cts, rts);
|
||||
}
|
||||
|
||||
// Set FIFO params
|
||||
if (param.esp32.fifo !== undefined) {
|
||||
let dfifo = param.esp32.fifo;
|
||||
|
||||
let ft = (dfifo.rxFullThresh !== undefined ? dfifo.rxFullThresh : -1);
|
||||
let fct = (dfifo.rxFcThresh !== undefined ? dfifo.rxFcThresh : -1);
|
||||
let alarm = (dfifo.rxAlarm !== undefined ? dfifo.rxAlarm : -1);
|
||||
let et = (dfifo.txEmptyThresh !== undefined ? dfifo.txEmptyThresh : -1);
|
||||
|
||||
this._fifo(uartNo, cfg, ft, fct, alarm, et);
|
||||
}
|
||||
},
|
||||
};
|
19
build/fs/api_bitbang.js
Normal file
19
build/fs/api_bitbang.js
Normal file
@@ -0,0 +1,19 @@
|
||||
let BitBang = {
|
||||
DELAY_MSEC: 0,
|
||||
DELAY_USEC: 1,
|
||||
DELAY_100NSEC: 2,
|
||||
|
||||
// ## **`BitBang.write(pin, delay_unit, t0h, t0l, t1h, t1l, ptr, len)`**
|
||||
// Write bits to a given `pin`. `delay_unit` is one of the:
|
||||
// `BitBang.DELAY_MSEC`, `BitBang.DELAY_USEC`, `BitBang.DELAY_100NSEC`.
|
||||
// `ptr, len` is a bit pattern to write. `t0h, t0l` is the time pattern
|
||||
// for zero bit, `t1h, t1l` is the time pattern for 1. The time pattern
|
||||
// specifies the number of time units to hold the pin high, and the number
|
||||
// of units to hold the pin low. Return value: none.
|
||||
write: function(pin, delay_unit, t0h, t0l, t1h, t1l, ptr, len) {
|
||||
let t = (t0h << 24) | (t0l << 16) | (t1h << 8) | t1l;
|
||||
this._wb(pin, delay_unit, t, ptr, len);
|
||||
},
|
||||
|
||||
_wb: ffi('void mgos_bitbang_write_bits_js(int, int, int, void *, int)'),
|
||||
};
|
63
build/fs/api_config.js
Normal file
63
build/fs/api_config.js
Normal file
@@ -0,0 +1,63 @@
|
||||
let Cfg = {
|
||||
_get: ffi('void *mgos_mjs_get_config()'),
|
||||
_set: ffi('bool mgos_config_apply(char *, bool)'),
|
||||
_desc: ffi('void *mgos_config_schema()'),
|
||||
_find: ffi('void *mgos_conf_find_schema_entry(char *, void *)'),
|
||||
_type: ffi('int mgos_conf_value_type(void *)'),
|
||||
_str: ffi('char *mgos_conf_value_string_nonnull(void *, void *)'),
|
||||
_int: ffi('int mgos_conf_value_int(void *, void *)'),
|
||||
_dbl: ffi('double mgos_conf_value_double(void *, void *)'),
|
||||
_INT: 0,
|
||||
_BOOL: 1,
|
||||
_DBL: 2,
|
||||
_STR: 3,
|
||||
_OBJ: 4,
|
||||
|
||||
// ## **`Cfg.get(path)`**
|
||||
// Get the config value by the configuration variable. Currently, only
|
||||
// simple types are returned: strings, ints, booleans, doubles. Objects
|
||||
// are not yet supported.
|
||||
//
|
||||
// Examples:
|
||||
// ```javascript
|
||||
// load('api_config.js');
|
||||
// Cfg.get('device.id'); // returns a string
|
||||
// Cfg.get('debug.level'); // returns an integer
|
||||
// Cfg.get('wifi.sta.enable'); // returns a boolean
|
||||
// ```
|
||||
get: function(path) {
|
||||
let entry = this._find(path, this._desc());
|
||||
if (entry === null) return undefined;
|
||||
let type = this._type(entry);
|
||||
let cfg = this._get();
|
||||
if (type === this._STR) {
|
||||
return this._str(cfg, entry);
|
||||
} else if (type === this._INT) {
|
||||
return this._int(cfg, entry);
|
||||
} else if (type === this._DBL) {
|
||||
return this._dbl(cfg, entry);
|
||||
} else if (type === this._BOOL) {
|
||||
return (this._int(cfg, entry) !== 0);
|
||||
} else if (type === this._OBJ) {
|
||||
/* TODO */
|
||||
return undefined;
|
||||
} else {
|
||||
/* TODO: an error */
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
// ## **`Cfg.set(obj, opt_save)`**
|
||||
// Set the configuration. `obj` must be a subset of the whole configuation
|
||||
// tree. `save` is boolean flag that indicating whether the change should
|
||||
// be saved - it could be omitted, in which case it defaults to `true`.
|
||||
// Examples:
|
||||
// ```javascript
|
||||
// load('api_config.js');
|
||||
// Cfg.set({wifi: {ap: {enable: false}}}); // Disable WiFi AP mode
|
||||
// Cfg.set({debug: {level: 3}}); // Set debug level to 3
|
||||
// ```
|
||||
set: function(obj, save) {
|
||||
return this._set(JSON.stringify(obj), save === undefined ? true : save);
|
||||
},
|
||||
};
|
222
build/fs/api_dataview.js
Normal file
222
build/fs/api_dataview.js
Normal file
@@ -0,0 +1,222 @@
|
||||
// **DataView API**
|
||||
//
|
||||
// See the original API definition at [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView).
|
||||
//
|
||||
// mJS DataView diverges from the original in the following ways:
|
||||
//
|
||||
// - No `ArrayBuffer`; plain pointers should be used instead;
|
||||
// - Since there are no constructors in mJS, `DataView.create()` should be
|
||||
// used instead;
|
||||
// - No float support yet (will be added)
|
||||
|
||||
let DataView = {
|
||||
// ## **`DataView.create(buf, offset, len)`**
|
||||
// Create a DataView object instance. `buf` is a pointer to a plain byte
|
||||
// array, `offset` is an offset in in this buffer to start dataview from, and
|
||||
// `len` is a length managed by dataview.
|
||||
//
|
||||
// Return value: an object with the methods described below.
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
// load("api_dataview.js");
|
||||
// let calloc = ffi('void *calloc(int, int)');
|
||||
// let ptr = calloc(100, 1);
|
||||
// let dw = DataView.create(ptr, 0, 100);
|
||||
//
|
||||
// dw.setUint8(2, 0xff);
|
||||
// ```
|
||||
create: function(buf, off, len) {
|
||||
let ret = Object.create(this._prot);
|
||||
if (off !== undefined) {
|
||||
buf += off;
|
||||
}
|
||||
ret._buf = buf;
|
||||
ret._len = len;
|
||||
return ret;
|
||||
},
|
||||
|
||||
_prot: {
|
||||
|
||||
// ## **`myDW.getInt8(idx)`**
|
||||
// Get a signed byte value from the dataview's buffer at the given index
|
||||
// `idx`. Returned value: a number from -128 to 127.
|
||||
getInt8: function(idx) {
|
||||
if (!DataView._cl(idx, this._len, 1)) {
|
||||
return undefined;
|
||||
}
|
||||
return DataView._gets(
|
||||
DataView._pk(this._buf, idx), 1, false
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.getUint8(idx)`**
|
||||
// Get an unsigned byte value from the dataview's buffer at the given index
|
||||
// `idx`. Returned value: a number from 0 to 255.
|
||||
getUint8: function(idx) {
|
||||
if (!DataView._cl(idx, this._len, 1)) {
|
||||
return undefined;
|
||||
}
|
||||
return DataView._getu(
|
||||
DataView._pk(this._buf, idx), 1, false
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.getInt16(idx, le)`**
|
||||
// Get a signed 2-byte value from the dataview's buffer at the given index
|
||||
// `idx`. By default the data interpreted as big-endian; if `le` is true,
|
||||
// then little-endian will be used.
|
||||
// Returned value: a number from -32768 to 32767.
|
||||
getInt16: function(idx, le) {
|
||||
if (!DataView._cl(idx, this._len, 2)) {
|
||||
return undefined;
|
||||
}
|
||||
return DataView._gets(
|
||||
DataView._pk(this._buf, idx), 2, !le
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.getUint16(idx, le)`**
|
||||
// Get an unsigned 2-byte value from the dataview's buffer at the given
|
||||
// index `idx`. By default the data interpreted as big-endian; if `le` is
|
||||
// true, then little-endian will be used.
|
||||
// Returned value: a number from 0 to 65535.
|
||||
getUint16: function(idx, le) {
|
||||
if (!DataView._cl(idx, this._len, 2)) {
|
||||
return undefined;
|
||||
}
|
||||
return DataView._getu(
|
||||
DataView._pk(this._buf, idx), 2, !le
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.getInt32(idx, le)`**
|
||||
// Get a signed 4-byte value from the dataview's buffer at the given index
|
||||
// `idx`. By default the data interpreted as big-endian; if `le` is true,
|
||||
// then little-endian will be used.
|
||||
// Returned value: a number from -2147483648 to 2147483647.
|
||||
getInt32: function(idx, le) {
|
||||
if (!DataView._cl(idx, this._len, 4)) {
|
||||
return undefined;
|
||||
}
|
||||
return DataView._gets(
|
||||
DataView._pk(this._buf, idx), 4, !le
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.getUint32(idx, le)`**
|
||||
// Get an unsigned 4-byte value from the dataview's buffer at the given
|
||||
// index `idx`. By default the data interpreted as big-endian; if `le` is
|
||||
// true, then little-endian will be used.
|
||||
// Returned value: a number from 0 to 4294967295.
|
||||
getUint32: function(idx, le) {
|
||||
if (!DataView._cl(idx, this._len, 4)) {
|
||||
return undefined;
|
||||
}
|
||||
return DataView._getu(
|
||||
DataView._pk(this._buf, idx), 4, !le
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.setInt8(idx, val)`**
|
||||
// Set a signed byte value into the dataview's buffer at the given index
|
||||
// `idx`. `val` should be a number from -128 to 127.
|
||||
// Returned value: none.
|
||||
setInt8: function(idx, val) {
|
||||
if (!DataView._cl(idx, this._len, 1)) {
|
||||
return undefined;
|
||||
}
|
||||
DataView._setu(
|
||||
DataView._pk(this._buf, idx), val, 1, false
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.setUint8(idx, val)`**
|
||||
// Set an unsigned byte value into the dataview's buffer at the given index
|
||||
// `idx`. `val` should be a number from -128 to 127.
|
||||
// Returned value: none.
|
||||
setUint8: function(idx, val) {
|
||||
if (!DataView._cl(idx, this._len, 1)) {
|
||||
return undefined;
|
||||
}
|
||||
DataView._setu(
|
||||
DataView._pk(this._buf, idx), val, 1, false
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.setInt16(idx, val, le)`**
|
||||
// Set a signed 2-byte value into the dataview's buffer at the given index
|
||||
// `idx`. `val` should be a number from -32768 to 32767. By default the
|
||||
// data is written in big-endian format; if `le` is true, then
|
||||
// little-endian will be used.
|
||||
// Returned value: none.
|
||||
setInt16: function(idx, val, le) {
|
||||
if (!DataView._cl(idx, this._len, 2)) {
|
||||
return undefined;
|
||||
}
|
||||
DataView._setu(
|
||||
DataView._pk(this._buf, idx), val, 2, !le
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.setUint16(idx, val, le)`**
|
||||
// Set an unsigned 2-byte value into the dataview's buffer at the given
|
||||
// index `idx`. `val` should be a number from 0 to 65535. By default the
|
||||
// data is written in big-endian format; if `le` is true, then
|
||||
// little-endian will be used.
|
||||
// Returned value: none.
|
||||
setUint16: function(idx, val, le) {
|
||||
if (!DataView._cl(idx, this._len, 2)) {
|
||||
return undefined;
|
||||
}
|
||||
DataView._setu(
|
||||
DataView._pk(this._buf, idx), val, 2, !le
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.setInt32(idx, val, le)`**
|
||||
// Set a signed 4-byte value into the dataview's buffer at the given index
|
||||
// `idx`. `val` should be a number from -2147483648 to 2147483647. By
|
||||
// default the data is written in big-endian format; if `le` is true, then
|
||||
// little-endian will be used.
|
||||
// Returned value: none.
|
||||
setInt32: function(idx, val, le) {
|
||||
if (!DataView._cl(idx, this._len, 4)) {
|
||||
return undefined;
|
||||
}
|
||||
DataView._setu(
|
||||
DataView._pk(this._buf, idx), val, 4, !le
|
||||
);
|
||||
},
|
||||
|
||||
// ## **`myDW.setUint32(idx, val, le)`**
|
||||
// Set an unsigned 4-byte value into the dataview's buffer at the given
|
||||
// index `idx`. `val` should be a number from 0 to 4294967295. By default
|
||||
// the data is written in big-endian format; if `le` is true, then
|
||||
// little-endian will be used.
|
||||
// Returned value: none.
|
||||
setUint32: function(idx, val, le) {
|
||||
if (!DataView._cl(idx, this._len, 4)) {
|
||||
return undefined;
|
||||
}
|
||||
DataView._setu(
|
||||
DataView._pk(this._buf, idx), val, 4, !le
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
_cl: function(idx, len, ilen) {
|
||||
if (len !== undefined && idx + ilen > len) {
|
||||
die(DataView._errm);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
_p: ffi('void *mjs_mem_to_ptr(int)'),
|
||||
_pk: ffi('void *mjs_mem_get_ptr(void *, int)'),
|
||||
_getu: ffi('double mjs_mem_get_uint(void *, int, int)'),
|
||||
_gets: ffi('double mjs_mem_get_int(void *, int, int)'),
|
||||
_setu: ffi('void mjs_mem_set_uint(void *, int, int, int)'),
|
||||
_errm: "Offset is outside of the bounds of the DataView",
|
||||
};
|
51
build/fs/api_dht.js
Normal file
51
build/fs/api_dht.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// Mongoose OS DHT library API. Source C API is defined at:
|
||||
// [mgos_dht.h](https://github.com/mongoose-os-libs/dht/tree/master/src/mgos_dht.h)
|
||||
|
||||
let DHT = {
|
||||
_crt: ffi('void *mgos_dht_create(int, int)'),
|
||||
_cls: ffi('void mgos_dht_close(void *)'),
|
||||
_gt: ffi('float mgos_dht_get_temp(void *)'),
|
||||
_gh: ffi('float mgos_dht_get_humidity(void *)'),
|
||||
|
||||
// Define type of sensors.
|
||||
DHT11: 11,
|
||||
DHT21: 21,
|
||||
AM2301: 21,
|
||||
DHT22: 22,
|
||||
AM2302: 22,
|
||||
|
||||
// **`DHT.create(pin, type)`**
|
||||
// Create a DHT object. `type` could be `DHT.DHT11`, `DHT.DHT21`,
|
||||
// `DHT.DHT22`. Return value: an object with the methods described below, or
|
||||
// 'null' in case of a failure.
|
||||
// Example:
|
||||
// ```javascript
|
||||
// let mydht = DHT.create(5, DHT.DHT11);
|
||||
// print('Temperature:', mydht.getTemp());
|
||||
// ```
|
||||
create: function(pin, type) {
|
||||
let obj = Object.create(DHT._proto);
|
||||
obj.dht = DHT._crt(pin, type);
|
||||
return obj;
|
||||
},
|
||||
|
||||
_proto: {
|
||||
// **`mydht.close()`**
|
||||
// Close DHT handle. Return value: none.
|
||||
close: function() {
|
||||
return DHT._cls(this.dht);
|
||||
},
|
||||
|
||||
// **`mydht.getTemp()`**
|
||||
// Return temperature in degrees C or 'NaN' in case of a failure.
|
||||
getTemp: function() {
|
||||
return DHT._gt(this.dht);
|
||||
},
|
||||
|
||||
// **`mydht.getHumidity()`**
|
||||
// Return humidity in RH% or 'NaN' in case of a failure.
|
||||
getHumidity: function() {
|
||||
return DHT._gh(this.dht);
|
||||
},
|
||||
},
|
||||
};
|
14
build/fs/api_esp32.js
Normal file
14
build/fs/api_esp32.js
Normal file
@@ -0,0 +1,14 @@
|
||||
let ESP32 = {
|
||||
// ## **`ESP32.temp()`**
|
||||
// Read built-in temperature sensor. Return value: integer.
|
||||
temp: ffi('int temprature_sens_read(void)'),
|
||||
|
||||
// ## **`ESP32.hall()`**
|
||||
// Read built-in Hall sensor. Return value: integer.
|
||||
hall: ffi('int hall_sens_read(void)'),
|
||||
|
||||
// ## **`ESP32.deepSleep(microseconds)`**
|
||||
// Deep Sleep given number of microseconds.
|
||||
// Return value: does not return.
|
||||
deepSleep: ffi('void mgos_esp_deep_sleep_d(double)'),
|
||||
};
|
102
build/fs/api_events.js
Normal file
102
build/fs/api_events.js
Normal file
@@ -0,0 +1,102 @@
|
||||
let Event = {
|
||||
// ## **`Event.addHandler(ev, callback, userdata)`**
|
||||
// Add a handler for the given event `ev`. Callback should look like:
|
||||
//
|
||||
// function(ev, evdata, userdata) { /* ... */ }
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
//
|
||||
// Event.addHandler(Event.REBOOT, function(ev, evdata, ud) {
|
||||
// print("Going to reboot!");
|
||||
// }, null);
|
||||
// ```
|
||||
addHandler: ffi(
|
||||
'bool mgos_event_add_handler(int, void(*)(int, void *, userdata), userdata)'),
|
||||
|
||||
// ## **`Event.addGroupHandler(evgrp, callback, userdata)`**
|
||||
// Like `Event.addHandler()`, but subscribes on all events in the given
|
||||
// event group `evgrp`. Event group includes all events from `evgrp & ~0xff`
|
||||
// to `evgrp | 0xff`.
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
//
|
||||
// Event.addGroupHandler(Event.SYS, function(ev, evdata, ud) {
|
||||
// print("Sys event:", ev);
|
||||
// }, null);
|
||||
// ```
|
||||
addGroupHandler: ffi(
|
||||
'bool mgos_event_add_group_handler(int, void(*)(int, void *, userdata), userdata)'),
|
||||
|
||||
// ## **`Event.regBase(base_event_number, name)`**
|
||||
// Register a base event number in order to prevent event number conflicts.
|
||||
// Use `Event.baseNumber(id)` to get `base_event_number`; `name` is an
|
||||
// arbitrary event name.
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
// let bn = Event.baseNumber("ABC");
|
||||
// if (!Event.regBase(bn, "My module")) {
|
||||
// die("Failed to register base event number");
|
||||
// }
|
||||
//
|
||||
// let MY_EVENT_FOO = bn + 0;
|
||||
// let MY_EVENT_BAR = bn + 1;
|
||||
// let MY_EVENT_BAZ = bn + 2;
|
||||
// ```
|
||||
regBase: ffi('bool mgos_event_register_base(int, char *)'),
|
||||
|
||||
// ## **`Event.baseNumber(id)`**
|
||||
// Generates unique base event number (32-bit) by a 3-char string.
|
||||
// LSB is always zero, and a library can use it to create up to 256 unique
|
||||
// events.
|
||||
//
|
||||
// A library should call `Event.regBase()` in order to claim
|
||||
// it and prevent event number conflicts. (see example there)
|
||||
baseNumber: function(id) {
|
||||
if (id.length !== 3) {
|
||||
die("Base event id should have exactly 3 chars");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (id.at(0) << 24) | (id.at(1) << 16) | (id.at(2) << 8);
|
||||
},
|
||||
|
||||
// ## **`Event.trigger(ev, evdata)`**
|
||||
// Trigger an event with the given id `ev` and event data `evdata`.
|
||||
trigger: ffi('int mgos_event_trigger(int, void *)'),
|
||||
|
||||
// ## **`Event.evdataLogStr(evdata)`**
|
||||
// Getter function for the `evdata` given to the event callback for the event
|
||||
// `Event.LOG`, see `Event.addHandler()`.
|
||||
evdataLogStr: function(evdata) {
|
||||
return mkstr(Event._gdd(evdata), 0, Event._gdl(evdata), true);
|
||||
},
|
||||
|
||||
_gdd: ffi('void *mgos_debug_event_get_ptr(void *)'),
|
||||
_gdl: ffi('int mgos_debug_event_get_len(void *)'),
|
||||
};
|
||||
|
||||
Event.SYS = Event.baseNumber("MOS");
|
||||
|
||||
// NOTE: INIT_DONE is unavailable here because init.js is executed in
|
||||
// INIT_DONE hook
|
||||
|
||||
// ## **`Event.LOG`**
|
||||
// System event which is triggered every time something is printed to the
|
||||
// log. In the callback, use `Event.evdataLogStr(evdata)` to get string
|
||||
// which was printed.
|
||||
Event.LOG = Event.SYS + 1;
|
||||
|
||||
// ## **`Event.REBOOT`**
|
||||
// System event which is triggered right before going to reboot. `evdata`
|
||||
// is irrelevant for this event.
|
||||
Event.REBOOT = Event.SYS + 2;
|
||||
|
||||
// ## **`Event.OTA_STATUS`**
|
||||
// System event which is triggered when OTA status changes.
|
||||
//
|
||||
// In the callback, use `OTA.evdataOtaStatusMsg(evdata)` from `api_ota.js` to
|
||||
// get the OTA status message.
|
||||
Event.OTA_STATUS = Event.SYS + 3;
|
63
build/fs/api_file.js
Normal file
63
build/fs/api_file.js
Normal file
@@ -0,0 +1,63 @@
|
||||
let File = {
|
||||
// **`File.read(name)`**
|
||||
// Read the whole file into a string variable.
|
||||
//
|
||||
// Return value: a string contents of the file.
|
||||
// If file does not exist, an empty string is returned.
|
||||
//
|
||||
// Example: read a .json configuration file into a config object:
|
||||
// ```javascript
|
||||
// let obj = JSON.parse(File.read('settings.json'));
|
||||
// ```
|
||||
read: function(path) {
|
||||
let n = 0; let res = ''; let buf = 'xxxxxxxxxx'; // Should be > 5
|
||||
let fp = File.fopen(path, 'r');
|
||||
if (fp === null) return null;
|
||||
while ((n = File.fread(buf, 1, buf.length, fp)) > 0) {
|
||||
res += buf.slice(0, n);
|
||||
}
|
||||
File.fclose(fp);
|
||||
return res;
|
||||
},
|
||||
|
||||
// **`File.remove(name)`**
|
||||
// Delete file with a given name. Return value: 0
|
||||
// on success, non-0 on failure.
|
||||
remove: ffi('int remove(char *)'),
|
||||
|
||||
// **`File.rename(old, new)`**
|
||||
// Rename file `old` to `new`. Return 0 on success, non-0 on failure.
|
||||
rename: ffi('int rename(char *, char *)'),
|
||||
|
||||
// **`File.write(str, name, mode)`**
|
||||
// Write string `str` into file `name`.
|
||||
//
|
||||
// If file does not exist, it is created. `mode` is an optional file open
|
||||
// mode argument, `'w'` by default, which means that previous content is
|
||||
// deleted. Set `mode` to `'a'` in order to append to the existing content.
|
||||
// Return value: number of bytes written.
|
||||
//
|
||||
// Example - write a configuration object into a file:
|
||||
// ```javascript
|
||||
// File.write(JSON.stringify(obj, 'settings.json'));
|
||||
// ```
|
||||
write: function(str, path, oMode) {
|
||||
let fp = File.fopen(path, oMode || 'w');
|
||||
if (fp === null) return 0;
|
||||
let off = 0; let tot = str.length;
|
||||
while (off < tot) {
|
||||
let len = 5; // Use light 5-byte strings for writing
|
||||
if (off + len > tot) len = tot - off;
|
||||
let n = File.fwrite(str.slice(off, off + len), 1, len, fp);
|
||||
// if (n <= 0) break;
|
||||
off += n;
|
||||
}
|
||||
File.fclose(fp);
|
||||
return off;
|
||||
},
|
||||
|
||||
fopen: ffi('void *fopen(char *, char *)'),
|
||||
fclose: ffi('void fclose(void *)'),
|
||||
fread: ffi('int fread(char *, int, int, void *)'),
|
||||
fwrite: ffi('int fwrite(char *, int, int, void *)'),
|
||||
};
|
75
build/fs/api_gpio.js
Normal file
75
build/fs/api_gpio.js
Normal file
@@ -0,0 +1,75 @@
|
||||
let GPIO = {
|
||||
// ## **`GPIO.set_mode(pin, mode)`**
|
||||
// Set GPIO pin mode.
|
||||
// `mode` can be either `GPIO.MODE_INPUT` or `GPIO.MODE_OUTPUT`.
|
||||
set_mode: ffi('int mgos_gpio_set_mode(int,int)'),
|
||||
MODE_INPUT: 0,
|
||||
MODE_OUTPUT: 1,
|
||||
|
||||
// ## **`GPIO.set_pull(pin, type)`**
|
||||
// Set GPIO pin pull type.
|
||||
// `type` can be either `GPIO.PULL_NONE`, `GPIO.PULL_UP`, or `GPIO.PULL_DOWN`.
|
||||
set_pull: ffi('int mgos_gpio_set_pull(int,int)'),
|
||||
PULL_NONE: 0,
|
||||
PULL_UP: 1,
|
||||
PULL_DOWN: 2,
|
||||
|
||||
// ## **`GPIO.toggle(pin)`**
|
||||
// Toggle the level of certain GPIO pin.
|
||||
// Return value: 0 or 1, indicating the resulting pin level.
|
||||
toggle: ffi('int mgos_gpio_toggle(int)'),
|
||||
|
||||
// ## **`GPIO.write(pin, level)`**
|
||||
// Set GPIO pin level to either 0 or 1. Return value: none.
|
||||
write: ffi('void mgos_gpio_write(int,int)'),
|
||||
|
||||
// ## **`GPIO.read(pin)`**
|
||||
// Read GPIO pin level. Return value: 0 or 1.
|
||||
read: ffi('int mgos_gpio_read(int)'),
|
||||
|
||||
// ## **`GPIO.enable_int(pin)`**
|
||||
// Enable interrupts on GPIO pin.
|
||||
// This function must be called AFTER the interrupt handler is installed.
|
||||
// Return value: 1 in case of success, 0 otherwise.
|
||||
enable_int: ffi('int mgos_gpio_enable_int(int)'),
|
||||
|
||||
// ## **`GPIO.disable_int(pin)`**
|
||||
// Disable interrupts on GPIO pin.
|
||||
// Return value: 1 in case of success, 0 otherwise.
|
||||
disable_int: ffi('int mgos_gpio_disable_int(int)'),
|
||||
|
||||
// ## **`GPIO.set_int_handler(pin, mode, handler)`**
|
||||
// Install GPIO interrupt handler. `mode` could be one of: `GPIO.INT_NONE`,
|
||||
// `GPIO.INT_EDGE_POS`, `GPIO.INT_EDGE_NEG`, `GPIO.INT_EDGE_ANY`,
|
||||
// `GPIO.INT_LEVEL_HI`, `GPIO.INT_LEVEL_LO`.
|
||||
// Return value: 1 in case of success, 0 otherwise.
|
||||
// Example:
|
||||
// ```javascript
|
||||
// GPIO.set_mode(pin, GPIO.MODE_INPUT);
|
||||
// GPIO.set_int_handler(pin, GPIO.INT_EDGE_NEG, function(pin) {
|
||||
// print('Pin', pin, 'got interrupt');
|
||||
// }, null);
|
||||
// GPIO.enable_int(pin);
|
||||
// ```
|
||||
set_int_handler: ffi('int mgos_gpio_set_int_handler(int,int,void(*)(int,userdata),userdata)'),
|
||||
INT_NONE: 0,
|
||||
INT_EDGE_POS: 1,
|
||||
INT_EDGE_NEG: 2,
|
||||
INT_EDGE_ANY: 3,
|
||||
INT_LEVEL_HI: 4,
|
||||
INT_LEVEL_LO: 5,
|
||||
|
||||
// ## **`GPIO.set_button_handler(pin, pull, intmode, period, handler)`**
|
||||
// Install
|
||||
// GPIO button handler. `pull` is pull type, `intmode` is interrupt mode,
|
||||
// `period` is debounce interval in milliseconds, handler is a function that
|
||||
// receives pin number.
|
||||
// Return value: 1 in case of success, 0 otherwise.
|
||||
// Example:
|
||||
// ```javascript
|
||||
// GPIO.set_button_handler(pin, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 200, function(x) {
|
||||
// print('Button press, pin: ', x);
|
||||
// }, null);
|
||||
// ```
|
||||
set_button_handler: ffi('int mgos_gpio_set_button_handler(int,int,int,int,void(*)(int, userdata), userdata)'),
|
||||
};
|
88
build/fs/api_grove.js
Normal file
88
build/fs/api_grove.js
Normal file
@@ -0,0 +1,88 @@
|
||||
load('api_gpio.js');
|
||||
load('api_adc.js');
|
||||
|
||||
let Grove = {
|
||||
Button: {
|
||||
// ## **`Grove.Button.attach(pin, handler)`**
|
||||
// Attach a handler for the button on the given pin. Example:
|
||||
// ```javascript
|
||||
// Grove.Button.attach(pin, function(pin) {
|
||||
// print('Button event at pin', pin);
|
||||
// }, null);
|
||||
// ```
|
||||
attach: function(pin, handler) {
|
||||
GPIO.set_button_handler(pin, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 200,
|
||||
handler, true);
|
||||
},
|
||||
},
|
||||
_motionHandler: undefined,
|
||||
MotionSensor: {
|
||||
// ## **`Grove.MotionSensor.attach(pin, handler)`**
|
||||
// Attach a handler for the motion sensor on the given pin. Example:
|
||||
// ```javascript
|
||||
// Grove.MotionSensor.attach(pin, function(pin) {
|
||||
// print('Motion sensor event at pin', pin);
|
||||
// }, null);
|
||||
// ```
|
||||
attach: function(pin, handler) {
|
||||
GPIO.set_mode(pin, GPIO.MODE_INPUT);
|
||||
GPIO.set_int_handler(pin, GPIO.INT_EDGE_POS, handler, null);
|
||||
GPIO.enable_int(pin);
|
||||
Grove._motionHandler = handler;
|
||||
},
|
||||
},
|
||||
LightSensor: {
|
||||
// ## **`Grove.LightSensor.get(pin)`**
|
||||
// Not implemented yet
|
||||
get: function(pin) {
|
||||
return ADC.read(pin);
|
||||
},
|
||||
},
|
||||
MoistureSensor: {
|
||||
// ## **`Grove.MoistureSensor.get(pin)`**
|
||||
// Not implemented yet
|
||||
get: function(pin) {
|
||||
return ADC.read(pin);
|
||||
},
|
||||
},
|
||||
UVSensor: {
|
||||
// ## **`Grove.MoistureSensor.get(pin)`**
|
||||
// Not implemented yet
|
||||
get: function(pin) {
|
||||
return ADC.read(pin);
|
||||
},
|
||||
},
|
||||
_relayInited: undefined,
|
||||
_relayClosed: 0,
|
||||
Relay: {
|
||||
_init: function(pin) {
|
||||
if (Grove._relayInited !== 1) {
|
||||
GPIO.set_mode(pin, GPIO.MODE_OUTPUT);
|
||||
GPIO.set_pull(pin, GPIO.PULL_DOWN);
|
||||
Grove._relayInited = 1;
|
||||
}
|
||||
},
|
||||
|
||||
// ## **`Grove.Relay.open(pin)`**
|
||||
// Open relay at the given pin.
|
||||
open: function(pin) {
|
||||
this._init(pin);
|
||||
GPIO.write(pin, 0);
|
||||
Grove._relayClosed = 0;
|
||||
},
|
||||
|
||||
// ## **`Grove.Relay.close(pin)`**
|
||||
// Close relay at the given pin.
|
||||
close: function(pin) {
|
||||
this._init(pin);
|
||||
GPIO.write(pin, 1);
|
||||
Grove._relayClosed = 1;
|
||||
},
|
||||
|
||||
// ## **`Grove.Relay.isClosed(pin)`**
|
||||
// Returns 0 if relay is opened, or 1 if it's closed.
|
||||
isClosed: function(pin) {
|
||||
return Grove._relayClosed;
|
||||
},
|
||||
},
|
||||
};
|
111
build/fs/api_http.js
Normal file
111
build/fs/api_http.js
Normal file
@@ -0,0 +1,111 @@
|
||||
load('api_net.js');
|
||||
|
||||
let URL = {
|
||||
// ## **`URL.parse(url)`**
|
||||
// Parse URL string, return and object with `ssl`, `addr`, `uri` keys.
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
// print(JSON.stringify(URL.parse('https://a.b:1234/foo?bar')));
|
||||
// // Prints: {"uri":"/foo?bar","addr":"a.b:1234","ssl":true}
|
||||
// ```
|
||||
parse: function(url) {
|
||||
let ssl = false, addr, port = '80', uri = '/', app = true;
|
||||
if (url.slice(0, 8) === 'https://') {
|
||||
port = '443';
|
||||
ssl = true;
|
||||
url = url.slice(8);
|
||||
}
|
||||
if (url.slice(0, 7) === 'http://') {
|
||||
url = url.slice(7);
|
||||
}
|
||||
addr = url;
|
||||
for (let i = 0; i < url.length; i++) {
|
||||
let ch = url[i];
|
||||
if (ch === ':') app = false;
|
||||
if (ch === '/') {
|
||||
addr = url.slice(0, i);
|
||||
uri = url.slice(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (app) addr += ':' + port;
|
||||
return {ssl: ssl, addr: addr, uri: uri};
|
||||
},
|
||||
};
|
||||
|
||||
let HTTP = {
|
||||
_getm: ffi('void *mgos_get_msg_ptr(void *)'),
|
||||
_getb: ffi('void *mgos_get_body_ptr(void *)'),
|
||||
_mgp: ffi('void *mgos_get_mgstr_ptr(void *)'),
|
||||
_mgl: ffi('int mgos_get_mgstr_len(void *)'),
|
||||
|
||||
_c: ffi('void *mgos_connect_http(char *, void (*)(void *, int, void *, userdata), userdata)'),
|
||||
_cs: ffi('void *mgos_connect_http_ssl(char *, void (*)(void *, int, void *, userdata), userdata, char *, char *, char *)'),
|
||||
_sp: ffi('void mg_set_protocol_http_websocket(void *)'),
|
||||
|
||||
_mstr: function(hmptr, func) {
|
||||
let mgstr = func(hmptr);
|
||||
return mkstr(this._mgp(mgstr), this._mgl(mgstr));
|
||||
},
|
||||
|
||||
// ## **`HTTP.query(options);`**
|
||||
// Send HTTP request. Options object accepts the following fields:
|
||||
// `url` - mandatory URL to fetch, `success` - optional callback function
|
||||
// that receives reply body, `error` - optional error callback that receives
|
||||
// error string, `data` - optional object with request parameters.
|
||||
// By default, `GET` method is used. If `data` is specified, POST method
|
||||
// is used, the `data` object gets `JSON.stringify()`-ed and used as a
|
||||
// HTTP message body.
|
||||
//
|
||||
// In order to send HTTPS request, use `https://...` URL. Note that in that
|
||||
// case `ca.pem` file must contain CA certificate of the requested server.
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
// HTTP.query({
|
||||
// url: 'http://httpbin.org/post',
|
||||
// headers: { 'X-Foo': 'bar' }, // Optional - headers
|
||||
// data: {foo: 1, bar: 'baz'}, // Optional. If set, JSON-encoded and POST-ed
|
||||
// success: function(body, full_http_msg) { print(body); },
|
||||
// error: function(err) { print(err); }, // Optional
|
||||
// });
|
||||
// ```
|
||||
query: function(opts) {
|
||||
let url = URL.parse(opts.url || '');
|
||||
return Net.connect({
|
||||
addr: url.addr,
|
||||
ssl: url.ssl,
|
||||
u: url,
|
||||
opts: opts,
|
||||
onconnect: function(conn, edata, ud) {
|
||||
let opts = ud.opts;
|
||||
let body = opts.data || '';
|
||||
if (typeof(body) !== 'string') body = JSON.stringify(body);
|
||||
let meth = body ? 'POST' : 'GET';
|
||||
let host = 'Host: ' + ud.u.addr + '\r\n';
|
||||
let cl = 'Content-Length: ' + JSON.stringify(body.length) + '\r\n';
|
||||
let hdrs = opts.headers || {};
|
||||
for (let k in hdrs) {
|
||||
cl += k + ': ' + hdrs[k] + '\r\n';
|
||||
}
|
||||
let req = meth + ' ' + ud.u.uri + ' HTTP/1.0\r\n' + host + cl + '\r\n';
|
||||
Net.send(conn, req);
|
||||
Net.send(conn, body);
|
||||
HTTP._sp(conn);
|
||||
},
|
||||
onevent: function(conn, buf, ev, edata, ud) {
|
||||
if (ev === 101 && ud.opts.success) {
|
||||
let body = HTTP._mstr(edata, HTTP._getb);
|
||||
let full = HTTP._mstr(edata, HTTP._getm);
|
||||
ud.opts.success(body, full);
|
||||
ud.ok = true;
|
||||
}
|
||||
},
|
||||
onclose: function(conn, ud) {
|
||||
let opts = ud.opts;
|
||||
if (!ud.ok && opts.error) opts.error('', 'Request failed', opts);
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
76
build/fs/api_log.js
Normal file
76
build/fs/api_log.js
Normal file
@@ -0,0 +1,76 @@
|
||||
let Log = {
|
||||
// ## **`Log.print(level, msg)`**
|
||||
// Print message to stderr if provided
|
||||
// level is >= `Cfg.get('debug.level')`. Possible levels are:
|
||||
// - `Log.ERROR` (0)
|
||||
// - `Log.WARN` (1)
|
||||
// - `Log.INFO` (2)
|
||||
// - `Log.DEBUG` (3)
|
||||
// - `Log.VERBOSE_DEBUG` (4)
|
||||
print: function(level, msg) {
|
||||
let mjs = getMJS();
|
||||
// Frame number: we're starting from the third frame, ignoring the first
|
||||
// two:
|
||||
// - this._off() or this._fn()
|
||||
// - Log.print()
|
||||
let cfn = 2;
|
||||
|
||||
// bcode offset of interest, and the corresponding function:lineno
|
||||
let offs, fn, ln;
|
||||
|
||||
// We'll go up by call trace until we find the frame not from the current
|
||||
// file
|
||||
while (true) {
|
||||
offs = this._off(mjs, cfn) - 1;
|
||||
fn = this._fn(mjs, offs);
|
||||
if (fn !== "api_log.js") {
|
||||
// Found the first frame from other file, we're done.
|
||||
break;
|
||||
}
|
||||
cfn++;
|
||||
}
|
||||
ln = this._ln(mjs, offs);
|
||||
this._pr(fn, ln, level, msg);
|
||||
},
|
||||
|
||||
// ## **`Log.error(msg)`**
|
||||
// Shortcut for `Log.print(Log.ERROR, msg)`
|
||||
error: function(msg) {
|
||||
this.print(this.ERROR, msg);
|
||||
},
|
||||
|
||||
// ## **`Log.warn(msg)`**
|
||||
// Shortcut for `Log.print(Log.WARN, msg)`
|
||||
warn: function(msg) {
|
||||
this.print(this.WARN, msg);
|
||||
},
|
||||
|
||||
// ## **`Log.info(msg)`**
|
||||
// Shortcut for `Log.print(Log.INFO, msg)`
|
||||
info: function(msg) {
|
||||
this.print(this.INFO, msg);
|
||||
},
|
||||
|
||||
// ## **`Log.debug(msg)`**
|
||||
// Shortcut for `Log.print(Log.DEBUG, msg)`
|
||||
debug: function(msg) {
|
||||
this.print(this.DEBUG, msg);
|
||||
},
|
||||
|
||||
// ## **`Log.verboseDebug(msg)`**
|
||||
// Shortcut for `Log.print(Log.VERBOSE_DEBUG, msg)`
|
||||
verboseDebug: function(msg) {
|
||||
this.print(this.VERBOSE_DEBUG, msg);
|
||||
},
|
||||
|
||||
ERROR: 0,
|
||||
WARN: 1,
|
||||
INFO: 2,
|
||||
DEBUG: 3,
|
||||
VERBOSE_DEBUG: 4,
|
||||
|
||||
_pr: ffi('void mgos_log(char *, int, int, char *)'),
|
||||
_fn: ffi('char *mjs_get_bcode_filename_by_offset(void *, int)'),
|
||||
_ln: ffi('int mjs_get_lineno_by_offset(void *, int)'),
|
||||
_off: ffi('int mjs_get_offset_by_call_frame_num(void *, int)'),
|
||||
};
|
62
build/fs/api_math.js
Normal file
62
build/fs/api_math.js
Normal file
@@ -0,0 +1,62 @@
|
||||
let Math = {
|
||||
|
||||
// ## **`Math.ceil(x)`**
|
||||
// Rounds x upward, returning the smallest integral value that is not less
|
||||
// than x.
|
||||
ceil: ffi('double ceil(double)'),
|
||||
|
||||
// ## **`Math.floor(x)`**
|
||||
// Rounds x downward, returning the largest integral value that is not
|
||||
// greater than x.
|
||||
floor: ffi('double floor(double)'),
|
||||
|
||||
// ## **`Math.round(x)`**
|
||||
// Returns the integral value that is nearest to x, with halfway cases
|
||||
// rounded away from zero.
|
||||
round: ffi('double round(double)'),
|
||||
|
||||
// ## **`Math.max(x, y)`**
|
||||
// Returns the larger of its arguments: either `x` or `y`.
|
||||
// If one of the arguments in a NaN, the other is returned.
|
||||
max: ffi('double fmax(double, double)'),
|
||||
|
||||
// ## **`Math.min(x, y)`**
|
||||
// Returns the smaller of its arguments: either `x` or `y`.
|
||||
// If one of the arguments in a NaN, the other is returned.
|
||||
min: ffi('double fmin(double, double)'),
|
||||
|
||||
// ## **`Math.abs(x)`**
|
||||
// Returns the absolute value of `x`: |x|.
|
||||
abs: ffi('double fabs(double)'),
|
||||
|
||||
// ## **`Math.sqrt(x)`**
|
||||
// Returns the square root of `x`.
|
||||
sqrt: ffi('double sqrt(double)'),
|
||||
|
||||
// ## **`Math.floor(x)`**
|
||||
// Returns the base-e exponential function of `x`, which is e raised to the
|
||||
// power `x`.
|
||||
exp: ffi('double exp(double)'),
|
||||
|
||||
// ## **`Math.log(x)`**
|
||||
// Returns the natural logarithm of `x`.
|
||||
log: ffi('double log(double)'),
|
||||
|
||||
// ## **`Math.pow(base, exponent)`**
|
||||
// Returns `base` raised to the power `exponent`
|
||||
pow: ffi('double pow(double, double)'),
|
||||
|
||||
// ## **`Math.sin(x)`**
|
||||
// Returns the sine of an angle of `x` radians.
|
||||
sin: ffi('double sin(double)'),
|
||||
|
||||
// ## **`Math.cos(x)`**
|
||||
// Returns the cosine of an angle of `x` radians.
|
||||
cos: ffi('double cos(double)'),
|
||||
|
||||
// ## **`Math.random(x)`**
|
||||
// Returns the pseudo-random number from 0.0 to 1.0
|
||||
random: function() { return Math.rand() / 0x7fffffff; },
|
||||
|
||||
rand: ffi('int rand()'),
|
||||
};
|
136
build/fs/api_net.js
Normal file
136
build/fs/api_net.js
Normal file
@@ -0,0 +1,136 @@
|
||||
load('api_events.js');
|
||||
|
||||
let Net = {
|
||||
_rb: ffi('void *mgos_get_recv_mbuf(void *)'),
|
||||
_mptr: ffi('void *mgos_get_mbuf_ptr(void *)'),
|
||||
_glen: ffi('int mgos_get_mbuf_len(void *)'),
|
||||
_mrem: ffi('void mbuf_remove(void *, int)'),
|
||||
_isin: ffi('bool mgos_is_inbound(void *)'),
|
||||
|
||||
_bind: ffi('void *mgos_bind(char *, void (*)(void *, int, void *, userdata), userdata)'),
|
||||
_c: ffi('void *mgos_connect(char *, void (*)(void *, int, void *, userdata), userdata)'),
|
||||
_cs: ffi('void *mgos_connect_ssl(char *, void (*)(void *, int, void *, userdata), userdata, char *, char *, char *)'),
|
||||
_send: ffi('void mg_send(void *, void *, int)'),
|
||||
_ctos: ffi('int mg_conn_addr_to_str(void *, char *, int, int)'),
|
||||
|
||||
// Return string contained in connection's recv_mbuf
|
||||
_rbuf: function(conn) {
|
||||
let rb = this._rb(conn);
|
||||
return mkstr(this._mptr(rb), this._glen(rb));
|
||||
},
|
||||
|
||||
// **`Net.ctos(conn, local, ip, port)`**
|
||||
// Convert address of a connection `conn` to string. Set `local` to
|
||||
// `true` to stringify local address, otherwise `false` to stringify remote.
|
||||
// Set `ip` to `true` to stringify IP, `port` to stringify port. Example:
|
||||
// ```javascript
|
||||
// print('Connection from:', Net.ctos(conn, false, true, true));
|
||||
// ```
|
||||
ctos: function(conn, local, ip, port) {
|
||||
let buf = ' ';
|
||||
let flags = (local ? 0 : 4) | (ip ? 1 : 0) | (port ? 2 : 0);
|
||||
let n = this._ctos(conn, buf, buf.length, flags);
|
||||
return buf.slice(0, n);
|
||||
},
|
||||
|
||||
// **`Net.discard(conn, len)`**
|
||||
// Remove initial `len` bytes of data from the connection's `conn`
|
||||
// receive buffer in order to discard that data and reclaim RAM to the system.
|
||||
discard: function(conn, len) {
|
||||
this._mrem(this._rb(conn), len);
|
||||
},
|
||||
|
||||
// Event handler. Expects an object with connect/data/close/event user funcs.
|
||||
_evh: function(conn, ev, edata, obj) {
|
||||
if (ev === 0) return;
|
||||
|
||||
if (ev === 1 || ev === 2) {
|
||||
if (obj.onconnect) obj.onconnect(conn, edata, obj);
|
||||
} else if (ev === 3) {
|
||||
if (obj.ondata) obj.ondata(conn, Net._rbuf(conn), obj);
|
||||
} else if (ev === 5) {
|
||||
if (obj.onclose) obj.onclose(conn, obj);
|
||||
let inb = Net._isin(conn); // Is this an inbound connection ?
|
||||
if (!inb) ffi_cb_free(Net._evh, obj);
|
||||
} else if (ev >= 6) {
|
||||
if (obj.onevent) obj.onevent(conn, Net._rbuf(conn), ev, edata, obj);
|
||||
}
|
||||
},
|
||||
|
||||
// ## **`Net.serve(options)`**
|
||||
// Start TCP or UDP server. `options` is an object:
|
||||
// ```javascript
|
||||
// {
|
||||
// // Required. Port to listen on, 'tcp://PORT' or `udp://PORT`.
|
||||
// addr: 'tcp://1234',
|
||||
// // Optional. Called when connection is established.
|
||||
// onconnect: function(conn) {},
|
||||
// // Optional. Called when new data is arrived.
|
||||
// ondata: function(conn, data) {},
|
||||
// // Optional. Called when protocol-specific event is triggered.
|
||||
// onevent: function(conn, data, ev, edata) {},
|
||||
// // Optional. Called when the connection is about to close.
|
||||
// onclose: function(conn) {},
|
||||
// // Optional. Called when on connection error.
|
||||
// onerror: function(conn) {},
|
||||
// }
|
||||
// ```
|
||||
// Example - a UDP echo server. Change `udp://` to `tcp://` to turn this
|
||||
// example into the TCP echo server:
|
||||
// ```javascript
|
||||
// Net.serve({
|
||||
// addr: 'udp://1234',
|
||||
// ondata: function(conn, data) {
|
||||
// print('Received from:', Net.ctos(conn, false, true, true), ':', data);
|
||||
// Net.send(conn, data); // Echo received data back
|
||||
// Net.discard(conn, data.length); // Discard received data
|
||||
// },
|
||||
// });
|
||||
// ```
|
||||
serve: function(obj) {
|
||||
return this._bind(obj.addr, this._evh, obj);
|
||||
},
|
||||
|
||||
// ## **`Net.connect(options)`**
|
||||
// Connect to a remote host. `options` is the same as for the `Net.serve`.
|
||||
// The addr format is `[PROTO://]HOST:PORT`. `PROTO` could be `tcp` or
|
||||
// `udp`. `HOST` could be an IP address or a host name. If `HOST` is a name,
|
||||
// it will be resolved asynchronously.
|
||||
//
|
||||
// Examples of valid addresses: `google.com:80`, `udp://1.2.3.4:53`,
|
||||
// `10.0.0.1:443`, `[::1]:80`.
|
||||
connect: function(obj) {
|
||||
if (obj.ssl) {
|
||||
return this._cs(obj.addr, this._evh, obj, obj.cert || '', obj.key || '', obj.ca_cert || 'ca.pem');
|
||||
} else {
|
||||
return this._c(obj.addr, this._evh, obj);
|
||||
}
|
||||
},
|
||||
|
||||
// ## **`Net.close(conn)`**
|
||||
// Send all pending data to the remote peer,
|
||||
// and disconnect when all data is sent.
|
||||
// Return value: none.
|
||||
close: ffi('void mgos_disconnect(void *)'),
|
||||
|
||||
// ## **`Net.send(conn, data)`**
|
||||
// Send data to the remote peer. `data` is an mJS string.
|
||||
// Return value: none.
|
||||
send: function(c, msg) {
|
||||
return Net._send(c, msg, msg.length);
|
||||
},
|
||||
|
||||
// ## **`Net.EVENT_GRP`**
|
||||
// Net events group, to be used with `Event.addGroupHandler()`. Possible
|
||||
// events are:
|
||||
// - `Net.STATUS_DISCONNECTED`
|
||||
// - `Net.STATUS_CONNECTING`
|
||||
// - `Net.STATUS_CONNECTED`
|
||||
// - `Net.STATUS_GOT_IP`
|
||||
EVENT_GRP: Event.baseNumber("NET"),
|
||||
};
|
||||
|
||||
Net.STATUS_DISCONNECTED = Net.EVENT_GRP + 0;
|
||||
Net.STATUS_CONNECTING = Net.EVENT_GRP + 1;
|
||||
Net.STATUS_CONNECTED = Net.EVENT_GRP + 2;
|
||||
Net.STATUS_GOT_IP = Net.EVENT_GRP + 3;
|
71
build/fs/api_rpc.js
Normal file
71
build/fs/api_rpc.js
Normal file
@@ -0,0 +1,71 @@
|
||||
let RPC = {
|
||||
_sdup: ffi('void *strdup(char *)'),
|
||||
_ah: ffi('void *mgos_rpc_add_handler(void *, void (*)(void *, char *, char *, userdata), userdata)'),
|
||||
_resp: ffi('bool mgos_rpc_send_response(void *, char *)'),
|
||||
_call: ffi('bool mgos_rpc_call(char *, char *, char *, void (*)(char *, int, char *, userdata), userdata)'),
|
||||
_err: ffi('bool mg_rpc_send_errorf(void *, int, char *, char *)'),
|
||||
|
||||
_ahcb: function(ri, args, src, ud) {
|
||||
// NOTE(lsm): not using `this` here deliberately. Calleth from C.
|
||||
let resp = ud.cb(JSON.parse(args || 'null'), src, ud.ud);
|
||||
if (typeof(resp) === 'object' && typeof(resp.error) === 'number') {
|
||||
RPC._err(ri, resp.error, '%s', resp.message || '');
|
||||
} else {
|
||||
RPC._resp(ri, JSON.stringify(resp));
|
||||
}
|
||||
// NOTE: we don't call ffi_cb_free here because this handler might be used
|
||||
// more than once
|
||||
},
|
||||
|
||||
_ccb: function(res, code, msg, ud) {
|
||||
ud.cb(res ? JSON.parse(res) : null, code, msg, ud.ud);
|
||||
ffi_cb_free(RPC._ccb, ud);
|
||||
},
|
||||
|
||||
LOCAL: "RPC.LOCAL",
|
||||
|
||||
// ## **`RPC.addHandler(name, handler)`**
|
||||
// Add RPC handler. `name` is a string like `'MyMethod'`, `handler`
|
||||
// is a callback function which takes `args` arguments object.
|
||||
// If a handler returns an object with a numeric `error` attribute and
|
||||
// optional `message` string attribute, the caller will get a failure.
|
||||
//
|
||||
// Return value: none.
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
// RPC.addHandler('Sum', function(args) {
|
||||
// if (typeof(args) === 'object' && typeof(args.a) === 'number' &&
|
||||
// typeof(args.b) === 'number') {
|
||||
// return args.a + args.b;
|
||||
// } else {
|
||||
// return {error: -1, message: 'Bad request. Expected: {"a":N1,"b":N2}'};
|
||||
// }
|
||||
// });
|
||||
// ```
|
||||
addHandler: function(name, cb, ud) {
|
||||
let data = {cb: cb, ud: ud};
|
||||
// TODO(lsm): get rid of this strdup() leak. One-off, but still ugly.
|
||||
this._ah(this._sdup(name), this._ahcb, data);
|
||||
},
|
||||
|
||||
// ## **`RPC.call(dst, method, args, callback)`**
|
||||
// Call remote or local RPC service.
|
||||
// Return value: true in case of success, false otherwise.
|
||||
//
|
||||
// If `dst` is empty, connected server is implied. `method` is a string
|
||||
// like "MyMethod", `callback` is a callback function which takes the following
|
||||
// arguments: res (results object), err_code (0 means success, or error code
|
||||
// otherwise), err_msg (error messasge for non-0 error code), userdata. Example:
|
||||
//
|
||||
// ```javascript
|
||||
// RPC.call(RPC.LOCAL, 'Config.Save', {reboot: true}, function (resp, ud) {
|
||||
// print('Response:', JSON.stringify(resp));
|
||||
// }, null);
|
||||
// ```
|
||||
call: function(dst, name, args, cb, ud) {
|
||||
let data = {cb: cb, ud: ud};
|
||||
return this._call(dst, name, JSON.stringify(args), this._ccb, data);
|
||||
},
|
||||
};
|
||||
|
46
build/fs/api_sys.js
Normal file
46
build/fs/api_sys.js
Normal file
@@ -0,0 +1,46 @@
|
||||
let Sys = {
|
||||
// ## **`Sys._sbuf(len)`**
|
||||
// Helper function to allocate string of at least given length. Note that
|
||||
// the resulting string is usually bigger than this, and it is always
|
||||
// longer than 5 bytes; that's to guarantee that the string data is stored in
|
||||
// a common buffer and not inlined into mjs_val_t, thus the buffer can be
|
||||
// used as an "output" buffer: a string can be passed to some function which
|
||||
// will alter the contents, and these changes will be visible to the caller.
|
||||
_sbuf: function(len) {
|
||||
let chunk = ' ', buf = chunk;
|
||||
while (buf.length < len) buf += chunk;
|
||||
return buf;
|
||||
},
|
||||
|
||||
// ## **`Sys.calloc(nmemb, size)`**
|
||||
// Allocate a memory region.
|
||||
// Note: currently memory allocated this way must be explicitly released with `free()`.
|
||||
malloc: ffi('void *malloc(int)'),
|
||||
free: ffi('void free(void *)'),
|
||||
|
||||
// ## **`Sys.total_ram()`**
|
||||
// Return total available RAM in bytes.
|
||||
total_ram: ffi('int mgos_get_heap_size()'),
|
||||
|
||||
// ## **`Sys.free_ram()`**
|
||||
// Return free available RAM in bytes.
|
||||
free_ram: ffi('int mgos_get_free_heap_size()'),
|
||||
|
||||
// ## **`Sys.reboot(us)`**
|
||||
// Reboot the system after `us` microseconds. Return value: none.
|
||||
reboot: ffi('void mgos_system_restart(int)'),
|
||||
|
||||
// ## **`Sys.uptime()`**
|
||||
// Return number of seconds since last reboot.
|
||||
uptime: ffi('double mgos_uptime()'),
|
||||
|
||||
// ## **`Sys.usleep(microseconds)`**
|
||||
// Sleep given number of microseconds.
|
||||
// Return value: none.
|
||||
usleep: ffi('void mgos_usleep(int)'),
|
||||
|
||||
// ## **`Sys.wdt_feed()`**
|
||||
// Feed the watchdog timer.
|
||||
// Return value: none.
|
||||
wdt_feed: ffi('void mgos_wdt_feed()')
|
||||
};
|
54
build/fs/api_timer.js
Normal file
54
build/fs/api_timer.js
Normal file
@@ -0,0 +1,54 @@
|
||||
load('api_math.js');
|
||||
|
||||
let Timer = {
|
||||
_f: ffi('int mgos_strftime(char *, int, char *, int)'),
|
||||
|
||||
// ## **`Timer.set(milliseconds, flags, handler, userdata)`**
|
||||
// Setup timer with `milliseconds` timeout and `handler` as a callback.
|
||||
// `flags` can be either 0 or `Timer.REPEAT`. In the latter case, the call
|
||||
// will be repeated indefinitely (but can be cancelled with `Timer.del()`),
|
||||
// otherwise it's a one-off.
|
||||
//
|
||||
// Return value: numeric timer ID.
|
||||
//
|
||||
// Example:
|
||||
// ```javascript
|
||||
// // Call every second
|
||||
// Timer.set(1000, Timer.REPEAT, function() {
|
||||
// let value = GPIO.toggle(2);
|
||||
// print(value ? 'Tick' : 'Tock');
|
||||
// }, null);
|
||||
// ```
|
||||
set: ffi('int mgos_set_timer(int,int,void(*)(userdata),userdata)'),
|
||||
|
||||
REPEAT: 1,
|
||||
|
||||
// ## **`Timer.now()`**
|
||||
// Return current time as double value, UNIX epoch (seconds since 1970).
|
||||
now: ffi('double mg_time(void)'),
|
||||
|
||||
// ## **`Timer.del(id)`**
|
||||
// Cancel previously installed timer.
|
||||
del: ffi('void mgos_clear_timer(int)'),
|
||||
|
||||
// ## **`Timer.fmt(fmt, time)`**
|
||||
// Formats the time 'time' according to the strftime-like format
|
||||
// specification 'fmt'. The strftime reference can be found e.g.
|
||||
// [here](http://www.cplusplus.com/reference/ctime/strftime/).
|
||||
// Example:
|
||||
// ```javascript
|
||||
// let now = Timer.now();
|
||||
// let s = Timer.fmt("Now it's %I:%M%p.", now);
|
||||
// print(s); // Example output: "Now it's 12:01AM."
|
||||
// ```
|
||||
fmt: function(fmt, time) {
|
||||
if (!fmt) return 'invalid format';
|
||||
let res = 0, t = Math.round(time || Timer.now()), s = ' ';
|
||||
while (res === 0) {
|
||||
res = this._f(s, s.length, fmt, t);
|
||||
if (res === -1) return 'invalid time';
|
||||
if (res === 0) s += ' ';
|
||||
}
|
||||
return s.slice(0, res);
|
||||
},
|
||||
};
|
165
build/fs/api_uart.js
Normal file
165
build/fs/api_uart.js
Normal file
@@ -0,0 +1,165 @@
|
||||
// UART API. Source C API is defined at:
|
||||
// [mgos_uart.h](https://github.com/cesanta/mongoose-os/blob/master/fw/src/mgos_uart.h)
|
||||
let UART = {
|
||||
_free: ffi('void free(void *)'),
|
||||
_cdef: ffi('void *mgos_uart_config_get_default(int)'),
|
||||
_cbp: ffi('void mgos_uart_config_set_basic_params(void *, int, int, int, int)'),
|
||||
_crx: ffi('void mgos_uart_config_set_rx_params(void *, int, int, int)'),
|
||||
_ctx: ffi('void mgos_uart_config_set_tx_params(void *, int, int)'),
|
||||
_cfg: ffi('int mgos_uart_configure(int, void *)'),
|
||||
_wr: ffi('int mgos_uart_write(int, char *, int)'),
|
||||
_rd: ffi('int mgos_uart_read(int, void *, int)'),
|
||||
|
||||
// ## **`UART.setConfig(uartNo, param)`**
|
||||
// Set UART config. `param` is an
|
||||
// object with the following optional fields:
|
||||
//
|
||||
// - `baudRate`: baud rate, integer, default: 115200;
|
||||
// - `numDataBits`: Number of data bits, default: 8;
|
||||
// - `parity`: Parity: 0 - none, 1 - even, 2 - odd; default: none;
|
||||
// - `numStopBits`: Number of stop bits: 1 - 1 bit, 2 - 2 bits, 3 - 1.5; default: 1;
|
||||
// - `rxBufSize`: size of the Rx buffer, integer, default: 256;
|
||||
// - `rxFlowControl`: whether Rx flow control (RTS pin) is enabled, boolean,
|
||||
// default: false;
|
||||
// - `rxLingerMicros`: how many microseconds to linger after Rx fifo
|
||||
// is empty, in case more data arrives. Integer, default: 15;
|
||||
// - `txBufSize`: size of the Tx buffer, integer, default: 256;
|
||||
// - `txFlowControl`: whether Tx flow control (CTS pin) is enabled, boolean,
|
||||
// default: false;
|
||||
//
|
||||
// Other than that, there are architecture-dependent settings, grouped in
|
||||
// the objects named with the architecture name: "esp32", "esp8266", etc.
|
||||
//
|
||||
// Settings for esp32:
|
||||
//
|
||||
// ```
|
||||
// esp32: {
|
||||
// /*
|
||||
// * GPIO pin numbers, default values depend on UART.
|
||||
// *
|
||||
// * UART 0: Rx: 3, Tx: 1, CTS: 19, RTS: 22
|
||||
// * UART 1: Rx: 13, Tx: 14, CTS: 15, RTS: 16
|
||||
// * UART 2: Rx: 17, Tx: 25, CTS: 26, RTS: 27
|
||||
// */
|
||||
// gpio: {
|
||||
// rx: number,
|
||||
// tx: number,
|
||||
// cts: number,
|
||||
// rts: number,
|
||||
// },
|
||||
//
|
||||
// /* Hardware FIFO tweaks */
|
||||
// fifo: {
|
||||
// /*
|
||||
// * A number of bytes in the hardware Rx fifo, should be between 1 and 127.
|
||||
// * How full hardware Rx fifo should be before "rx fifo full" interrupt is
|
||||
// * fired.
|
||||
// */
|
||||
// rxFullThresh: number,
|
||||
//
|
||||
// /*
|
||||
// * A number of bytes in the hardware Rx fifo, should be more than
|
||||
// * rx_fifo_full_thresh.
|
||||
// *
|
||||
// * How full hardware Rx fifo should be before CTS is deasserted, telling
|
||||
// * the other side to stop sending data.
|
||||
// */
|
||||
// rxFcThresh: number,
|
||||
//
|
||||
// /*
|
||||
// * Time in uart bit intervals when "rx fifo full" interrupt fires even if
|
||||
// * it's not full enough
|
||||
// */
|
||||
// rxAlarm: number,
|
||||
//
|
||||
// /*
|
||||
// * A number of bytes in the hardware Tx fifo, should be between 1 and 127.
|
||||
// * When the number of bytes in Tx buffer becomes less than
|
||||
// * tx_fifo_empty_thresh, "tx fifo empty" interrupt fires.
|
||||
// */
|
||||
// txEmptyThresh: number,
|
||||
// },
|
||||
// }
|
||||
// ```
|
||||
setConfig: function(uartNo, param) {
|
||||
let cfg = this._cdef(uartNo);
|
||||
|
||||
this._cbp(cfg, param.baudRate || 115200,
|
||||
param.numDataBits || 8,
|
||||
param.parity || 0,
|
||||
param.numStopBits || 1);
|
||||
|
||||
this._crx(
|
||||
cfg,
|
||||
param.rxBufSize || 256,
|
||||
param.rxFlowControl || false,
|
||||
param.rxLingerMicros || 15
|
||||
);
|
||||
|
||||
this._ctx(
|
||||
cfg,
|
||||
param.txBufSize || 256,
|
||||
param.txFlowControl || false
|
||||
);
|
||||
|
||||
// Apply arch-specific config
|
||||
if (this._arch !== undefined) {
|
||||
this._arch.scfg(uartNo, cfg, param);
|
||||
}
|
||||
|
||||
let res = this._cfg(uartNo, cfg);
|
||||
|
||||
this._free(cfg);
|
||||
cfg = null;
|
||||
|
||||
return res;
|
||||
},
|
||||
|
||||
// ## **`UART.setDispatcher(uartNo, callback, userdata)`**
|
||||
// Set UART dispatcher
|
||||
// callback which gets invoked when there is a new data in the input buffer
|
||||
// or when the space becomes available on the output buffer.
|
||||
//
|
||||
// Callback receives the following arguments: `(uartNo, userdata)`.
|
||||
setDispatcher: ffi('void mgos_uart_set_dispatcher(int, void(*)(int, userdata), userdata)'),
|
||||
|
||||
// ## **`UART.write(uartNo, data)`**
|
||||
// Write data to the buffer. Returns number of bytes written.
|
||||
//
|
||||
// Example usage: `UART.write(1, "foobar")`, in this case, 6 bytes will be written.
|
||||
write: function(uartNo, data) {
|
||||
this._wr(uartNo, data, data.length);
|
||||
},
|
||||
|
||||
// ## **`UART.writeAvail(uartNo)`**
|
||||
// Return amount of space available in the output buffer.
|
||||
writeAvail: ffi('int mgos_uart_write_avail(int)'),
|
||||
|
||||
// ## **`UART.read(uartNo)`**
|
||||
// It never blocks, and returns a string containing
|
||||
// read data (which will be empty if there's no data available).
|
||||
read: function(uartNo) {
|
||||
let n = 0; let res = ''; let buf = 'xxxxxxxxxx'; // Should be > 5
|
||||
while ((n = this._rd(uartNo, buf, buf.length)) > 0) {
|
||||
res += buf.slice(0, n);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
// ## **`UART.readAvail(uartNo)`**
|
||||
// Return amount of data available in the input buffer.
|
||||
readAvail: ffi('int mgos_uart_read_avail(int)'),
|
||||
|
||||
// ## **`UART.setRxEnabled(uartNo)`**
|
||||
// Set whether Rx is enabled.
|
||||
setRxEnabled: ffi('void mgos_uart_set_rx_enabled(int, int)'),
|
||||
// ## **`UART.isRxEnabled(uartNo)`**
|
||||
// Returns whether Rx is enabled.
|
||||
isRxEnabled: ffi('int mgos_uart_is_rx_enabled(int)'),
|
||||
|
||||
// ## **`UART.flush(uartNo)`**
|
||||
// Flush the UART output buffer, wait for the data to be sent.
|
||||
flush: ffi('void mgos_uart_flush(int)'),
|
||||
};
|
||||
|
||||
// Load arch-specific API
|
||||
load('api_arch_uart.js');
|
36
build/fs/api_wifi.js
Normal file
36
build/fs/api_wifi.js
Normal file
@@ -0,0 +1,36 @@
|
||||
// Wifi global object is created during C initialization.
|
||||
|
||||
// ## **`Wifi.scan(cb)`**
|
||||
// Scan WiFi networks, call `cb` when done.
|
||||
// `cb` accepts a single argument `results`, which is
|
||||
// either `undefined` in case of error, or an array of object containing:
|
||||
// ```javascript
|
||||
// {
|
||||
// "ssid": "NetworkName",
|
||||
// "bssid": "12:34:56:78:90:ab",
|
||||
// "authMode": Wifi.AUTH_MODE_WPA_PSK, // Auth mode, one of AUTH constants.
|
||||
// "channel": 11,
|
||||
// "rssi": -70
|
||||
// }
|
||||
// ```
|
||||
// Example:
|
||||
// ```javascript
|
||||
// Wifi.scan(function(results) {
|
||||
// print(JSON.stringify(results));
|
||||
// });
|
||||
// ```
|
||||
|
||||
// Must be kept in sync with enum mgos_wifi_auth_mode
|
||||
// ## **Auth modes**
|
||||
// - `Wifi.AUTH_MODE_OPEN`
|
||||
// - `Wifi.AUTH_MODE_WEP`
|
||||
// - `Wifi.AUTH_MODE_WPA_PSK`
|
||||
// - `Wifi.AUTH_MODE_WPA2_PSK`
|
||||
// - `Wifi.AUTH_MODE_WPA_WPA2_PSK`
|
||||
// - `Wifi.AUTH_MODE_WPA2_ENTERPRISE`
|
||||
Wifi.AUTH_MODE_OPEN = 0;
|
||||
Wifi.AUTH_MODE_WEP = 1;
|
||||
Wifi.AUTH_MODE_WPA_PSK = 2;
|
||||
Wifi.AUTH_MODE_WPA2_PSK = 3;
|
||||
Wifi.AUTH_MODE_WPA_WPA2_PSK = 4;
|
||||
Wifi.AUTH_MODE_WPA2_ENTERPRISE = 5;
|
298
build/fs/ca.pem
Normal file
298
build/fs/ca.pem
Normal file
@@ -0,0 +1,298 @@
|
||||
Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
|
||||
Not Before: Sep 30 21:12:19 2000 GMT
|
||||
Not After : Sep 30 14:01:15 2021 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
|
||||
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
||||
Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
|
||||
rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
|
||||
OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
|
||||
xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
|
||||
7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
|
||||
aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
|
||||
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
|
||||
SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
|
||||
ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
|
||||
AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
|
||||
R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root
|
||||
Not Before: May 12 18:46:00 2000 GMT
|
||||
Not After : May 12 23:59:00 2025 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
|
||||
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
|
||||
VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
|
||||
DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
|
||||
ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
|
||||
VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
|
||||
mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
|
||||
IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
|
||||
mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
|
||||
XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
|
||||
dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
|
||||
jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
|
||||
BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
|
||||
DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
|
||||
9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
|
||||
jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
|
||||
Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
|
||||
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
|
||||
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
|
||||
Not Before: May 21 04:00:00 2002 GMT
|
||||
Not After : May 21 04:00:00 2022 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 ECC 256 bit SSL CA - G2
|
||||
Not Before: May 12 00:00:00 2015 GMT
|
||||
Not After : May 11 23:59:59 2025 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEajCCA1KgAwIBAgIQP5KHvp0dpKN6nfYoLndaxDANBgkqhkiG9w0BAQsFADCB
|
||||
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IC0gRzUwHhcNMTUwNTEyMDAwMDAwWhcNMjUwNTExMjM1OTU5WjCBgDEL
|
||||
MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
|
||||
VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMTEwLwYDVQQDEyhTeW1hbnRlYyBD
|
||||
bGFzcyAzIEVDQyAyNTYgYml0IFNTTCBDQSAtIEcyMFkwEwYHKoZIzj0CAQYIKoZI
|
||||
zj0DAQcDQgAEDxukkdfnrOfRTk63ZFvhj39uBNOrONtEt0Bcbb2WljffeYmGZ/ex
|
||||
Hwie/WM7RoyfvVPoFdyXPiuBRq2Gfw4BOaOCAV0wggFZMC4GCCsGAQUFBwEBBCIw
|
||||
IDAeBggrBgEFBQcwAYYSaHR0cDovL3Muc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwZQYDVR0gBF4wXDBaBgpghkgBhvhFAQc2MEwwIwYIKwYBBQUHAgEWF2h0
|
||||
dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5z
|
||||
eW1jYi5jb20vcnBhMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9zLnN5bWNiLmNv
|
||||
bS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKwYDVR0RBCQwIqQgMB4xHDAa
|
||||
BgNVBAMTE1NZTUMtRUNDLUNBLXAyNTYtMjIwHQYDVR0OBBYEFCXwiuFLetkBlQrt
|
||||
xlPxjHgf2fP4MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQAMMGUXBaWTdaLxsTGtcB/naqjIQrLvoV9NG+7MoHpGd/69
|
||||
dZ/h2zOy7sGFUHoG/0HGRA9rxT/5w5GkEVIVkxtWyIWWq6rs4CTZt8Bej/KHYRbo
|
||||
jtEDUkCTZSTLiCvguPyvinXgxy+LHT+PmdtEfXsvcdbeBSWUYpOsDYvD2hNtz9dw
|
||||
Od5nBosMApmdxt+z7LQyZu8wMnfI1U6IMO+RWowxZ8uy0oswdFYd32l9xe+aAE/k
|
||||
y9alLu/M9pvxiUKufqHJRgDBKA6uDjHLMPX+/nxXaNCPX3SI4KVZ1stHQ/U5oNlM
|
||||
dHN9umAvlU313g0IgJrjsQ2nIdf9dsdP+6lrmP7s
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
|
||||
Not Before: Nov 8 00:00:00 2006 GMT
|
||||
Not After : Jul 16 23:59:59 2036 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
|
||||
Not Before: Jun 29 17:06:20 2004 GMT
|
||||
Not After : Jun 29 17:06:20 2034 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
|
||||
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
|
||||
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
|
||||
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
|
||||
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
|
||||
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
|
||||
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
|
||||
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
|
||||
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
|
||||
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
|
||||
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
|
||||
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
|
||||
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
|
||||
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
|
||||
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
|
||||
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
|
||||
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
|
||||
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
|
||||
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
|
||||
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
|
||||
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
|
||||
ReYNnyicsbkqWletNw+vHX/bvZ8=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
|
||||
Not Before: Jun 29 17:39:16 2004 GMT
|
||||
Not After : Jun 29 17:39:16 2034 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
|
||||
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
|
||||
U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
|
||||
NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
|
||||
ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
|
||||
ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
|
||||
8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
|
||||
+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
|
||||
X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
|
||||
K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
|
||||
1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
|
||||
A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
|
||||
zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
|
||||
YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
|
||||
bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
|
||||
DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
|
||||
L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
|
||||
eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
|
||||
xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
|
||||
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
|
||||
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Not Before: Sep 1 00:00:00 2009 GMT
|
||||
Not After : Dec 31 23:59:59 2037 GMT
|
||||
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||
ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
|
||||
MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
|
||||
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
|
||||
aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
|
||||
Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
|
||||
nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
|
||||
HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
|
||||
Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
|
||||
dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
|
||||
HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
|
||||
sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
|
||||
4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
|
||||
8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
|
||||
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
|
||||
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2
|
||||
Not Before: Sep 1 00:00:00 2009 GMT
|
||||
Not After : Dec 31 23:59:59 2037 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
||||
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
||||
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
||||
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
||||
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
||||
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
||||
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
||||
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
||||
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
||||
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
||||
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
||||
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
||||
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
||||
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
||||
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
||||
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
||||
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
||||
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
||||
sSi6
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
|
||||
Not Before: Dec 15 08:00:00 2006 GMT
|
||||
Not After : Dec 15 08:00:00 2021 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
|
||||
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
|
||||
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
|
||||
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
|
||||
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
|
||||
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
|
||||
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
|
||||
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
|
||||
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
|
||||
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
|
||||
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
|
||||
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
|
||||
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
|
||||
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
|
||||
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
|
||||
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
|
||||
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
|
||||
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
|
||||
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
|
||||
Not Before: Nov 10 00:00:00 2006 GMT
|
||||
Not After : Nov 10 00:00:00 2031 GMT
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
+OkuE6N36B9K
|
||||
-----END CERTIFICATE-----
|
115
build/fs/conf0.json
Normal file
115
build/fs/conf0.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"device": {
|
||||
"id": "HiGrow_??????",
|
||||
"password": ""
|
||||
},
|
||||
"debug": {
|
||||
"udp_log_addr": "",
|
||||
"level": 2,
|
||||
"filter": "",
|
||||
"stdout_uart": 0,
|
||||
"stderr_uart": 0,
|
||||
"factory_reset_gpio": -1,
|
||||
"mg_mgr_hexdump_file": "",
|
||||
"mbedtls_level": 0
|
||||
},
|
||||
"sys": {
|
||||
"mount": {
|
||||
"path": "",
|
||||
"dev_type": "",
|
||||
"dev_opts": "",
|
||||
"fs_type": "",
|
||||
"fs_opts": ""
|
||||
},
|
||||
"tz_spec": "",
|
||||
"wdt_timeout": 30,
|
||||
"pref_ota_lib": "",
|
||||
"esp32_adc_vref": 0
|
||||
},
|
||||
"conf_acl": "*",
|
||||
"bt": {
|
||||
"enable": true,
|
||||
"dev_name": "HiGrowBT_",
|
||||
"adv_enable": true,
|
||||
"scan_rsp_data_hex": "",
|
||||
"keep_enabled": false,
|
||||
"allow_pairing": true,
|
||||
"max_paired_devices": -1,
|
||||
"random_address": true,
|
||||
"gatts": {
|
||||
"min_sec_level": 0,
|
||||
"require_pairing": false
|
||||
},
|
||||
"config_svc_enable": true
|
||||
},
|
||||
"mjs": {
|
||||
"generate_jsc": true
|
||||
},
|
||||
"rpc": {
|
||||
"enable": true,
|
||||
"max_frame_size": 4096,
|
||||
"max_queue_length": 25,
|
||||
"default_out_channel_idle_close_timeout": 10,
|
||||
"acl_file": "",
|
||||
"auth_domain": "",
|
||||
"auth_file": "",
|
||||
"ws": {
|
||||
"enable": true,
|
||||
"server_address": "",
|
||||
"reconnect_interval_min": 1,
|
||||
"reconnect_interval_max": 60,
|
||||
"ssl_server_name": "",
|
||||
"ssl_ca_file": "",
|
||||
"ssl_client_cert_file": ""
|
||||
},
|
||||
"uart": {
|
||||
"uart_no": 0,
|
||||
"baud_rate": 115200,
|
||||
"fc_type": 2,
|
||||
"wait_for_start_frame": true
|
||||
}
|
||||
},
|
||||
"wifi": {
|
||||
"sta": {
|
||||
"enable": false,
|
||||
"ssid": "",
|
||||
"pass": "",
|
||||
"user": "",
|
||||
"anon_identity": "",
|
||||
"cert": "",
|
||||
"key": "",
|
||||
"ca_cert": "",
|
||||
"ip": "",
|
||||
"netmask": "",
|
||||
"gw": "",
|
||||
"nameserver": "",
|
||||
"dhcp_hostname": ""
|
||||
},
|
||||
"ap": {
|
||||
"enable": false,
|
||||
"ssid": "Mongoose_??????",
|
||||
"pass": "Mongoose",
|
||||
"hidden": false,
|
||||
"channel": 6,
|
||||
"max_connections": 10,
|
||||
"ip": "192.168.4.1",
|
||||
"netmask": "255.255.255.0",
|
||||
"gw": "192.168.4.1",
|
||||
"dhcp_start": "192.168.4.2",
|
||||
"dhcp_end": "192.168.4.100",
|
||||
"trigger_on_gpio": -1,
|
||||
"disable_after": 0,
|
||||
"hostname": "",
|
||||
"keep_enabled": true
|
||||
}
|
||||
},
|
||||
"higrow": {
|
||||
"deviceId": "",
|
||||
"temperature": 0.0,
|
||||
"humidity": 0.0,
|
||||
"light": 0,
|
||||
"moisture": 0,
|
||||
"connected": false,
|
||||
"battery_calibration": 2360
|
||||
}
|
||||
}
|
95
build/fs/init.js
Normal file
95
build/fs/init.js
Normal file
@@ -0,0 +1,95 @@
|
||||
load('api_config.js');
|
||||
load('api_events.js');
|
||||
load('api_gpio.js');
|
||||
load('api_http.js');
|
||||
load('api_net.js');
|
||||
load('api_sys.js');
|
||||
load('api_timer.js');
|
||||
load('api_esp32.js');
|
||||
load('api_dht.js');
|
||||
load('api_adc.js');
|
||||
load('api_rpc.js');
|
||||
|
||||
//Pins
|
||||
let ResetPin = 0;
|
||||
let LedPin = 16;
|
||||
let DHTpin = 22;
|
||||
let SOILpin = 32;
|
||||
let LIGHTpin = 34;
|
||||
|
||||
// Turn on status led
|
||||
GPIO.set_mode(LedPin, GPIO.MODE_OUTPUT);
|
||||
GPIO.write(LedPin, 0);
|
||||
|
||||
//Reset Handler
|
||||
GPIO.set_mode(ResetPin, GPIO.MODE_INPUT);
|
||||
GPIO.set_int_handler(ResetPin, GPIO.INT_EDGE_NEG, function(ResetPin) {
|
||||
print('Pin', ResetPin, 'got interrupt');
|
||||
GPIO.toggle(LedPin);
|
||||
Sys.usleep(200000);
|
||||
GPIO.toggle(LedPin);
|
||||
Sys.usleep(200000);
|
||||
GPIO.toggle(LedPin);
|
||||
Sys.usleep(200000);
|
||||
GPIO.toggle(LedPin);
|
||||
Sys.usleep(200000);
|
||||
GPIO.toggle(LedPin);
|
||||
Sys.usleep(200000);
|
||||
GPIO.write(LedPin, 0);
|
||||
|
||||
Cfg.set({bt:{enable:true}});
|
||||
Cfg.set({wifi:{sta:{enable:false}}});
|
||||
Cfg.set({wifi:{ap:{enable:false}}});
|
||||
Cfg.set({wifi:{sta:{ssid:'',pass:''}}});
|
||||
|
||||
Sys.reboot(1000);
|
||||
}, null);
|
||||
GPIO.enable_int(ResetPin);
|
||||
|
||||
ADC.enable(SOILpin);
|
||||
let dht = DHT.create(DHTpin, DHT.DHT11);
|
||||
let deviceId = Cfg.get("higrow.deviceId");
|
||||
if (deviceId === "")
|
||||
{
|
||||
deviceId = Cfg.get("device.id");
|
||||
Cfg.set("higrow.devideId", deviceId);
|
||||
}
|
||||
|
||||
let connected = false;
|
||||
let readSensors = Timer.set(15000, Timer.REPEAT, function() {
|
||||
let t = dht.getTemp();
|
||||
let h = dht.getHumidity();
|
||||
let m = ADC.read(SOILpin);
|
||||
let l = ADC.read(LIGHTpin);
|
||||
|
||||
print("DeviceId:", deviceId,"Temperature:",t,"Humidity:",h,"Moisture:",m,"Light:",l);
|
||||
|
||||
//Timer.del(readSensors);
|
||||
|
||||
//ESP32.deepSleep(3600000000); //3600 seconds / 60 minutes
|
||||
/*
|
||||
Cfg.set({higrow:{temperature:jsonData.Temperature}});
|
||||
Cfg.set({higrow:{moisture:jsonData.Water}});
|
||||
Cfg.set({higrow:{humidity:jsonData.Humidity}});
|
||||
Cfg.set({higrow:{light:jsonData.Light}});
|
||||
*/
|
||||
}, null);
|
||||
|
||||
// Monitor network connectivity.
|
||||
Event.addGroupHandler(Net.EVENT_GRP, function(ev, evdata, arg) {
|
||||
let status = true && connected;
|
||||
let evs = '???';
|
||||
if (ev === Net.STATUS_DISCONNECTED) {
|
||||
evs = 'DISCONNECTED';
|
||||
connected = false;
|
||||
} else if (ev === Net.STATUS_CONNECTING) {
|
||||
evs = 'CONNECTING';
|
||||
connected = false;
|
||||
} else if (ev === Net.STATUS_CONNECTED) {
|
||||
evs = 'CONNECTED';
|
||||
connected = false;
|
||||
} else if (ev === Net.STATUS_GOT_IP) {
|
||||
evs = 'GOT_IP';
|
||||
connected = true;
|
||||
}
|
||||
}, null);
|
Reference in New Issue
Block a user