/*JSON{ "type" : "staticmethod", "class" : "ESP8266WiFi", "name" : "onWiFiEvent", "generate" : "jswrap_ESP8266WiFi_onWiFiEvent", "params" : [ ["callback","JsVar","WiFi event callback"] ] }*/ void jswrap_ESP8266WiFi_onWiFiEvent( JsVar *callback //!< WiFi event callback. ) { // If the callback is null if (callback == NULL || jsvIsNull(callback)) { if (g_jsWiFiEventCallback != NULL) { jsvUnLock(g_jsWiFiEventCallback); } g_jsWiFiEventCallback = NULL; return; } if (!jsvIsFunction(callback)) { jsExceptionHere(JSET_ERROR, "No callback."); return; } // We are about to save a new global WiFi even callback handler. If we have previously // had one, we need to unlock it so that we don't leak memory. if (g_jsWiFiEventCallback != NULL) { jsvUnLock(g_jsWiFiEventCallback); } // Save the global WiFi event callback handler. g_jsWiFiEventCallback = jsvLockAgainSafe(callback); }
/*JSON{ "type":"method", "class": "Serial", "name" : "setup", "description" : "Setup this Serial port with the given baud rate and options", "generate" : "jswrap_serial_setup", "params" : [ [ "baudrate", "int", "The baud rate - the default is 9600"], [ "options", "JsVar", ["An optional structure containing extra information on initialising the serial port.", "```{rx:pin,tx:pin}```", "Note that even after changing the RX and TX pins, if you have called setup before then the previous RX and TX pins will still be connected to the Serial port as well - until you set them to something else using digitalWrite" ] ] ] }*/ void jswrap_serial_setup(JsVar *parent, JsVarInt baud, JsVar *options) { IOEventFlags device = jsiGetDeviceFromClass(parent); JshUSARTInfo inf; jshUSARTInitInfo(&inf); if (baud>0) inf.baudRate = (int)baud; if (jsvIsObject(options)) { inf.pinRX = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "rx", 0)); inf.pinTX = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "tx", 0)); inf.bytesize = (unsigned char)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "bytesize", 0)); JsVar *v; v = jsvObjectGetChild(options, "parity", 0); if(jsvIsNull(v)) { inf.parity = 0; } else if(jsvIsString(v)) { inf.parity = 0xFF; char s[8] = ""; jsvGetString(v, s, sizeof(s) - 1); if(!strcmp(s, "o") || !strcmp(s, "odd")) { inf.parity = 1; } else if(!strcmp(s, "e") || !strcmp(s, "even")) { inf.parity = 2; } } else if(jsvIsInt(v)) { inf.parity = (unsigned char)jsvGetInteger(v); } jsvUnLock(v); v = jsvObjectGetChild(options, "stopbits", 0); inf.stopbits = (unsigned char)jsvGetInteger(v); jsvUnLock(v); } jshUSARTSetup(device, &inf); // Set baud rate in object, so we can initialise it on startup if (baud != DEFAULT_BAUD_RATE) { JsVar *baudVar = jsvNewFromInteger(baud); jsvUnLock(jsvSetNamedChild(parent, baudVar, USART_BAUDRATE_NAME)); jsvUnLock(baudVar); } else jsvRemoveNamedChild(parent, USART_BAUDRATE_NAME); // Do the same for options if (options) jsvUnLock(jsvSetNamedChild(parent, options, DEVICE_OPTIONS_NAME)); else jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); }
/*JSON{ "type" : "method", "class" : "String", "name" : "match", "generate" : "jswrap_string_match", "params" : [ ["subStr","JsVar","Substring or RegExp to match"] ], "return" : ["JsVar","This match array"] } Matches `subStr` occurrence in the string. */ JsVar *jswrap_string_match(JsVar *parent, JsVar *subStr) { if (!jsvIsString(parent)) return 0; if (jsvIsUndefined(subStr)) return 0; #ifndef SAVE_ON_FLASH // Use RegExp if one is passed in if (jsvIsInstanceOf(subStr, "RegExp")) { jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); JsVar *match; match = jswrap_regexp_exec(subStr, parent); if (!jswrap_regexp_hasFlag(subStr,'g')) { return match; } // global JsVar *array = jsvNewEmptyArray(); if (!array) return 0; // out of memory while (match && !jsvIsNull(match)) { // get info about match JsVar *matchStr = jsvGetArrayItem(match,0); JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0)); JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr); int last = idx+len; jsvArrayPushAndUnLock(array, matchStr); // search again jsvUnLock(match); jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(last)); match = jswrap_regexp_exec(subStr, parent); } jsvUnLock(match); jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); return array; } #endif subStr = jsvAsString(subStr); int idx = jswrap_string_indexOf(parent, subStr, 0, false); if (idx>=0) { JsVar *array = jsvNewEmptyArray(); if (!array) { jsvUnLock(subStr); return 0; // out of memory } jsvArrayPush(array, subStr); jsvObjectSetChildAndUnLock(array, "index", jsvNewFromInteger(idx)); jsvObjectSetChildAndUnLock(array, "input", subStr); return array; } jsvUnLock(subStr); return NULL; }
/*JSON{ "type" : "staticmethod", "class" : "Object", "name" : "create", "generate" : "jswrap_object_create", "params" : [ ["proto","JsVar","A prototype object"], ["propertiesObject","JsVar","An object containing properties. NOT IMPLEMENTED"] ], "return" : ["JsVar","A new object"] } Creates a new object with the specified prototype object and properties. properties are currently unsupported. */ JsVar *jswrap_object_create(JsVar *proto, JsVar *propertiesObject) { if (!jsvIsObject(proto) && !jsvIsNull(proto)) { jsWarn("Object prototype may only be an Object or null: %t", proto); return 0; } if (jsvIsObject(propertiesObject)) { jsWarn("propertiesObject is not supported yet"); } JsVar *obj = jsvNewObject(); if (!obj) return 0; if (jsvIsObject(proto)) jsvObjectSetChild(obj, JSPARSE_INHERITS_VAR, proto); return obj; }
/*JSON{ "type" : "staticmethod", "class" : "ESP8266WiFi", "name" : "ping", "generate" : "jswrap_ESP8266WiFi_ping", "params" : [ ["ipAddr","JsVar","A string or integer representation of an IP address."], ["pingCallback", "JsVar", "Optional callback function."] ] }*/ void jswrap_ESP8266WiFi_ping( JsVar *ipAddr, //!< A string or integer representation of an IP address. JsVar *pingCallback //!< Optional callback function. ) { // If the parameter is a string, get the IP address from the string // representation. if (jsvIsString(ipAddr)) { char ipString[20]; int len = jsvGetString(ipAddr, ipString, sizeof(ipString)-1); ipString[len] = '\0'; pingOpt.ip = networkParseIPAddress(ipString); if (pingOpt.ip == 0) { jsExceptionHere(JSET_ERROR, "Not a valid IP address."); return; } } else // If the parameter is an integer, treat it as an IP address. if (jsvIsInt(ipAddr)) { pingOpt.ip = jsvGetInteger(ipAddr); } else // The parameter was neither a string nor an IP address and hence we don't // know how to get the IP address of the partner to ping so throw an // exception. { jsExceptionHere(JSET_ERROR, "IP address must be string or integer."); return; } if (jsvIsUndefined(pingCallback) || jsvIsNull(pingCallback)) { if (g_jsPingCallback != NULL) { jsvUnLock(g_jsPingCallback); } g_jsPingCallback = NULL; } else if (!jsvIsFunction(pingCallback)) { jsExceptionHere(JSET_ERROR, "Callback is not a function."); return; } else { if (g_jsPingCallback != NULL) { jsvUnLock(g_jsPingCallback); } g_jsPingCallback = pingCallback; jsvLockAgainSafe(g_jsPingCallback); } // We now have an IP address to ping ... so ping. memset(&pingOpt, 0, sizeof(pingOpt)); pingOpt.count = 5; pingOpt.recv_function = pingRecvCB; ping_start(&pingOpt); }
/*JSON{ "type" : "staticmethod", "class" : "JSON", "name" : "stringify", "generate" : "jswrap_json_stringify", "params" : [ ["data","JsVar","The data to be converted to a JSON string"], ["replacer","JsVar","This value is ignored"], ["space","JsVar","The number of spaces to use for padding, a string, or null/undefined for no whitespace "] ], "return" : ["JsVar","A JSON string"] } Convert the given object into a JSON string which can subsequently be parsed with JSON.parse or eval. **Note:** This differs from JavaScript's standard `JSON.stringify` in that: * The `replacer` argument is ignored * Typed arrays like `new Uint8Array(5)` will be dumped as if they were arrays, not as if they were objects (since it is more compact) */ JsVar *jswrap_json_stringify(JsVar *v, JsVar *replacer, JsVar *space) { NOT_USED(replacer); JSONFlags flags = JSON_IGNORE_FUNCTIONS|JSON_NO_UNDEFINED|JSON_ARRAYBUFFER_AS_ARRAY; JsVar *result = jsvNewFromEmptyString(); if (result) {// could be out of memory char whitespace[11] = ""; if (jsvIsUndefined(space) || jsvIsNull(space)) { // nothing } else if (jsvIsNumeric(space)) { unsigned int s = (unsigned int)jsvGetInteger(space); if (s>10) s=10; whitespace[s] = 0; while (s) whitespace[--s]=' '; } else { jsvGetString(space, whitespace, sizeof(whitespace)); } if (strlen(whitespace)) flags |= JSON_ALL_NEWLINES|JSON_PRETTY; jsfGetJSONWhitespace(v, result, flags, whitespace); } return result; }
bool jsonNeedsNewLine(JsVar *v) { return !(jsvIsUndefined(v) || jsvIsNull(v) || jsvIsNumeric(v)); // we're skipping strings here because they're usually long and want printing on multiple lines }
/*JSON{ "type" : "method", "class" : "Serial", "name" : "setup", "generate" : "jswrap_serial_setup", "params" : [ ["baudrate","JsVar","The baud rate - the default is 9600"], ["options","JsVar",["An optional structure containing extra information on initialising the serial port.","```{rx:pin,tx:pin,bytesize:8,parity:null/'none'/'o'/'odd'/'e'/'even',stopbits:1,flow:null/undefined/'none'/'xon'}```","You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `UART`/`USART` markers.","Note that even after changing the RX and TX pins, if you have called setup before then the previous RX and TX pins will still be connected to the Serial port as well - until you set them to something else using digitalWrite"]] ] } Setup this Serial port with the given baud rate and options. If not specified in options, the default pins are used (usually the lowest numbered pins on the lowest port that supports this peripheral) */ void jswrap_serial_setup(JsVar *parent, JsVar *baud, JsVar *options) { IOEventFlags device = jsiGetDeviceFromClass(parent); if (!DEVICE_IS_USART(device)) return; JshUSARTInfo inf; jshUSARTInitInfo(&inf); if (jsvIsUndefined(options)) { options = jsvObjectGetChild(parent, DEVICE_OPTIONS_NAME, 0); } else jsvLockAgain(options); JsVar *parity = 0; JsVar *flow = 0; jsvConfigObject configs[] = { {"rx", JSV_PIN, &inf.pinRX}, {"tx", JSV_PIN, &inf.pinTX}, {"ck", JSV_PIN, &inf.pinCK}, {"bytesize", JSV_INTEGER, &inf.bytesize}, {"stopbits", JSV_INTEGER, &inf.stopbits}, {"parity", JSV_OBJECT /* a variable */, &parity}, {"flow", JSV_OBJECT /* a variable */, &flow}, }; if (!jsvIsUndefined(baud)) { int b = (int)jsvGetInteger(baud); if (b<=100 || b > 10000000) jsExceptionHere(JSET_ERROR, "Invalid baud rate specified"); else inf.baudRate = b; } bool ok = true; if (jsvReadConfigObject(options, configs, sizeof(configs) / sizeof(jsvConfigObject))) { // sort out parity inf.parity = 0; if(jsvIsString(parity)) { if (jsvIsStringEqual(parity, "o") || jsvIsStringEqual(parity, "odd")) inf.parity = 1; else if (jsvIsStringEqual(parity, "e") || jsvIsStringEqual(parity, "even")) inf.parity = 2; } else if (jsvIsInt(parity)) { inf.parity = (unsigned char)jsvGetInteger(parity); } if (inf.parity>2) { jsExceptionHere(JSET_ERROR, "Invalid parity %d", inf.parity); ok = false; } if (ok) { if (jsvIsUndefined(flow) || jsvIsNull(flow) || jsvIsStringEqual(flow, "none")) inf.xOnXOff = false; else if (jsvIsStringEqual(flow, "xon")) inf.xOnXOff = true; else { jsExceptionHere(JSET_ERROR, "Invalid flow control: %q", flow); ok = false; } } #ifdef LINUX if (ok && jsvIsObject(options)) jsvObjectSetChildAndUnLock(parent, "path", jsvObjectGetChild(options, "path", 0)); #endif } jsvUnLock(parity); jsvUnLock(flow); if (!ok) { jsvUnLock(options); return; } jshUSARTSetup(device, &inf); // Set baud rate in object, so we can initialise it on startup jsvObjectSetChildAndUnLock(parent, USART_BAUDRATE_NAME, jsvNewFromInteger(inf.baudRate)); // Do the same for options if (options) jsvObjectSetChildAndUnLock(parent, DEVICE_OPTIONS_NAME, options); else jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); }
/*JSON{ "type" : "staticmethod", "class" : "ESP8266WiFi", "name" : "connect", "generate" : "jswrap_ESP8266WiFi_connect", "params" : [ ["ssid","JsVar","The network id of the access point."], ["password","JsVar","The password to the access point"], ["gotIpCallback", "JsVar", "An optional callback invoked when we have an IP"] ] } * * Connect the station to an access point. */ void jswrap_ESP8266WiFi_connect( JsVar *jsv_ssid, //!< The SSID of the access point to connect. JsVar *jsv_password, //!< The password for the access point. JsVar *gotIpCallback //!< The Callback function to be called when we are connected. ) { os_printf("> jswrap_ESP8266WiFi_connect\n"); // Check that the ssid and password values aren't obviously in error. if (jsv_ssid == NULL || !jsvIsString(jsv_ssid)) { jsExceptionHere(JSET_ERROR, "No SSID."); return; } if (jsv_password == NULL || !jsvIsString(jsv_password)) { jsExceptionHere(JSET_ERROR, "No password."); return; } // Check that if a callback function was supplied that we actually have a callback function. if (gotIpCallback != NULL && !jsvIsUndefined(gotIpCallback) && !jsvIsFunction(gotIpCallback)) { gotIpCallback = NULL; jsExceptionHere(JSET_ERROR, "A callback function was supplied that is not a function."); return; } if (jsvIsUndefined(gotIpCallback) || jsvIsNull(gotIpCallback)) { gotIpCallback = NULL; } // Set the global which is the gotIP callback to null but first unlock it. if (g_jsGotIpCallback != NULL) { jsvUnLock(g_jsGotIpCallback); g_jsGotIpCallback = NULL; } // If we have a callback, save it for later invocation. if (gotIpCallback != NULL) { g_jsGotIpCallback = jsvLockAgainSafe(gotIpCallback); } // Debug // os_printf("jsGotIpCallback=%p\n", jsGotIpCallback); // Create strings from the JsVars for the ESP8266 API calls. char ssid[33]; int len = jsvGetString(jsv_ssid, ssid, sizeof(ssid)-1); ssid[len]='\0'; char password[65]; len = jsvGetString(jsv_password, password, sizeof(password)-1); password[len]='\0'; os_printf("> - ssid=%s, password=%s\n", ssid, password); // Set the WiFi mode of the ESP8266 wifi_set_opmode_current(STATION_MODE); struct station_config stationConfig; memset(&stationConfig, 0, sizeof(stationConfig)); os_strncpy((char *)stationConfig.ssid, ssid, 32); if (password != NULL) { os_strncpy((char *)stationConfig.password, password, 64); } else { os_strcpy((char *)stationConfig.password, ""); } // Set the WiFi configuration wifi_station_set_config(&stationConfig); uint8 wifiConnectStatus = wifi_station_get_connect_status(); os_printf(" - Current connect status: %s\n", wifiConnectStatusToString(wifiConnectStatus)); if (wifiConnectStatus == STATION_GOT_IP) { // See issue #618. There are currently three schools of thought on what should happen // when a connect is issued and we are already connected. // // Option #1 - Always perform a disconnect. // Option #2 - Perform a disconnect if the SSID or PASSWORD are different from current // Option #3 - Fail the connect if we are already connected. // #define ISSUE_618 1 #if ISSUE_618 == 1 wifi_station_disconnect(); #elif ISSUE_618 == 2 struct station_config existingConfig; wifi_station_get_config(&existingConfig); if (os_strncmp((char *)existingConfig.ssid, (char *)stationConfig.ssid, 32) == 0 && os_strncmp((char *)existingConfig.password, (char *)stationConfig.password, 64) == 0) { if (jsGotIpCallback != NULL) { JsVar *params[2]; params[0] = jsvNewFromInteger(STATION_GOT_IP); params[1] = jsvNewNull(); jsiQueueEvents(NULL, jsGotIpCallback, params, 2); } return; } else { wifi_station_disconnect(); } #elif ISSUE_618 == 3 // Add a return code to the function and return an already connected error. #endif } // Perform the network level connection. wifi_station_connect(); os_printf("< jswrap_ESP8266WiFi_connect\n"); }
/*JSON{ "type" : "staticmethod", "class" : "url", "name" : "parse", "generate" : "jswrap_url_parse", "params" : [ ["urlStr","JsVar","A URL to be parsed"], ["parseQuery","bool","Whether to parse the query string into an object not (default = false)"] ], "return" : ["JsVar","An object containing options for ```http.request``` or ```http.get```. Contains `method`, `host`, `path`, `pathname`, `search`, `port` and `query`"] } A utility function to split a URL into parts This is useful in web servers for instance when handling a request. For instance `url.parse("/a?b=c&d=e",true)` returns `{"method":"GET","host":"","path":"/a?b=c&d=e","pathname":"/a","search":"?b=c&d=e","port":80,"query":{"b":"c","d":"e"}}` */ JsVar *jswrap_url_parse(JsVar *url, bool parseQuery) { if (!jsvIsString(url)) return 0; JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0; // out of memory // scan string to try and pick stuff out JsvStringIterator it; jsvStringIteratorNew(&it, url, 0); int slashes = 0; int colons = 0; int addrStart = -1; int portStart = -1; int pathStart = -1; int searchStart = -1; int charIdx = 0; int portNumber = 0; while (jsvStringIteratorHasChar(&it)) { char ch = jsvStringIteratorGetChar(&it); if (ch == '/') { slashes++; if (pathStart<0) pathStart = charIdx; if (colons==1 && slashes==2 && addrStart<0) { addrStart = charIdx; pathStart = -1; searchStart = -1; } } if (ch == ':') { colons++; if (addrStart>=0 && pathStart<0) portStart = charIdx; } if (portStart>=0 && charIdx>portStart && pathStart<0 && ch >= '0' && ch <= '9') { portNumber = portNumber*10 + (ch-'0'); } if (ch == '?' && pathStart>=0) { searchStart = charIdx; } jsvStringIteratorNext(&it); charIdx++; } jsvStringIteratorFree(&it); // try and sort stuff out if (pathStart<0) pathStart = charIdx; if (pathStart<0) pathStart = charIdx; int addrEnd = (portStart>=0) ? portStart : pathStart; // pull out details if (addrStart>0) jsvObjectSetChildAndUnLock(obj, "protocol", jsvNewFromStringVar(url, 0, (size_t)addrStart-1)); jsvObjectSetChildAndUnLock(obj, "method", jsvNewFromString("GET")); jsvObjectSetChildAndUnLock(obj, "host", jsvNewFromStringVar(url, (size_t)(addrStart+1), (size_t)(addrEnd-(addrStart+1)))); JsVar *v; v = jsvNewFromStringVar(url, (size_t)pathStart, JSVAPPENDSTRINGVAR_MAXLENGTH); if (jsvGetStringLength(v)==0) jsvAppendString(v, "/"); jsvObjectSetChildAndUnLock(obj, "path", v); v = jsvNewFromStringVar(url, (size_t)pathStart, (size_t)((searchStart>=0)?(searchStart-pathStart):JSVAPPENDSTRINGVAR_MAXLENGTH)); if (jsvGetStringLength(v)==0) jsvAppendString(v, "/"); jsvObjectSetChildAndUnLock(obj, "pathname", v); jsvObjectSetChildAndUnLock(obj, "search", (searchStart>=0)?jsvNewFromStringVar(url, (size_t)searchStart, JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull()); jsvObjectSetChildAndUnLock(obj, "port", (portNumber<=0 || portNumber>65535) ? jsvNewWithFlags(JSV_NULL) : jsvNewFromInteger(portNumber)); JsVar *query = (searchStart>=0)?jsvNewFromStringVar(url, (size_t)(searchStart+1), JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull(); if (parseQuery && !jsvIsNull(query)) { JsVar *queryStr = query; jsvStringIteratorNew(&it, query, 0); query = jsvNewWithFlags(JSV_OBJECT); JsVar *key = jsvNewFromEmptyString(); JsVar *val = jsvNewFromEmptyString(); bool hadEquals = false; while (jsvStringIteratorHasChar(&it)) { char ch = jsvStringIteratorGetChar(&it); if (ch=='&') { if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) { key = jsvAsArrayIndexAndUnLock(key); // make sure "0" gets made into 0 jsvMakeIntoVariableName(key, val); jsvAddName(query, key); jsvUnLock2(key, val); key = jsvNewFromEmptyString(); val = jsvNewFromEmptyString(); hadEquals = false; } } else if (!hadEquals && ch=='=') { hadEquals = true; } else { // decode percent escape chars if (ch=='%') { jsvStringIteratorNext(&it); ch = jsvStringIteratorGetChar(&it); jsvStringIteratorNext(&it); ch = (char)((chtod(ch)<<4) | chtod(jsvStringIteratorGetChar(&it))); } if (hadEquals) jsvAppendCharacter(val, ch); else jsvAppendCharacter(key, ch); } jsvStringIteratorNext(&it); charIdx++; } jsvStringIteratorFree(&it); jsvUnLock(queryStr); if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) { key = jsvAsArrayIndexAndUnLock(key); // make sure "0" gets made into 0 jsvMakeIntoVariableName(key, val); jsvAddName(query, key); } jsvUnLock2(key, val); } jsvObjectSetChildAndUnLock(obj, "query", query); return obj; }
/*JSON{ "type" : "method", "class" : "Serial", "name" : "setup", "generate" : "jswrap_serial_setup", "params" : [ ["baudrate","JsVar","The baud rate - the default is 9600"], ["options","JsVar",["An optional structure containing extra information on initialising the serial port.","```{rx:pin,tx:pin,bytesize:8,parity:null/'none'/'o'/'odd'/'e'/'even',stopbits:1,flow:null/undefined/'none'/'xon'}```","You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `UART`/`USART` markers.","Note that even after changing the RX and TX pins, if you have called setup before then the previous RX and TX pins will still be connected to the Serial port as well - until you set them to something else using digitalWrite"]] ] } Setup this Serial port with the given baud rate and options. If not specified in options, the default pins are used (usually the lowest numbered pins on the lowest port that supports this peripheral) */ void jswrap_serial_setup(JsVar *parent, JsVar *baud, JsVar *options) { IOEventFlags device = jsiGetDeviceFromClass(parent); if (!DEVICE_IS_USART(device)) return; JshUSARTInfo inf; jshUSARTInitInfo(&inf); if (!jsvIsUndefined(baud)) { int b = (int)jsvGetInteger(baud); if (b<=100 || b > 10000000) jsExceptionHere(JSET_ERROR, "Invalid baud rate specified"); else inf.baudRate = b; } if (jsvIsObject(options)) { inf.pinRX = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "rx", 0)); inf.pinTX = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "tx", 0)); inf.pinCK = jshGetPinFromVarAndUnLock(jsvObjectGetChild(options, "ck", 0)); JsVar *v; v = jsvObjectGetChild(options, "bytesize", 0); if (jsvIsInt(v)) inf.bytesize = (unsigned char)jsvGetInteger(v); jsvUnLock(v); inf.parity = 0; v = jsvObjectGetChild(options, "parity", 0); if(jsvIsString(v)) { if(jsvIsStringEqual(v, "o") || jsvIsStringEqual(v, "odd")) inf.parity = 1; else if(jsvIsStringEqual(v, "e") || jsvIsStringEqual(v, "even")) inf.parity = 2; } else if(jsvIsInt(v)) { inf.parity = (unsigned char)jsvGetInteger(v); } jsvUnLock(v); if (inf.parity>2) { jsExceptionHere(JSET_ERROR, "Invalid parity %d", inf.parity); return; } v = jsvObjectGetChild(options, "stopbits", 0); if (jsvIsInt(v)) inf.stopbits = (unsigned char)jsvGetInteger(v); jsvUnLock(v); v = jsvObjectGetChild(options, "flow", 0); if(jsvIsUndefined(v) || jsvIsNull(v) || jsvIsStringEqual(v, "none")) inf.xOnXOff = false; else if(jsvIsStringEqual(v, "xon")) inf.xOnXOff = true; else jsExceptionHere(JSET_ERROR, "Invalid flow control: %q", v); jsvUnLock(v); #ifdef LINUX jsvUnLock(jsvObjectSetChild(parent, "path", jsvObjectGetChild(options, "path", 0))); #endif } jshUSARTSetup(device, &inf); // Set baud rate in object, so we can initialise it on startup jsvUnLock(jsvObjectSetChild(parent, USART_BAUDRATE_NAME, jsvNewFromInteger(inf.baudRate))); // Do the same for options if (options) jsvUnLock(jsvSetNamedChild(parent, options, DEVICE_OPTIONS_NAME)); else jsvRemoveNamedChild(parent, DEVICE_OPTIONS_NAME); }
/*JSON{ "type" : "method", "ifndef" : "SAVE_ON_FLASH", "class" : "RegExp", "name" : "test", "params" : [ ["str","JsVar","A string to match on"] ], "generate" : "jswrap_regexp_test", "return" : ["bool","true for a match, or false"] } Test this regex on a string - returns `true` on a successful match, or `false` otherwise */ bool jswrap_regexp_test(JsVar *parent, JsVar *str) { JsVar *v = jswrap_regexp_exec(parent, str); bool r = v && !jsvIsNull(v); jsvUnLock(v); return r; }
/*JSON{ "type" : "method", "class" : "String", "name" : "split", "generate" : "jswrap_string_split", "params" : [ ["separator","JsVar","The separator `String` or `RegExp` to use"] ], "return" : ["JsVar","Part of this string from start for len characters"] } Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==['1', '2', '3']``` Regular Expressions can also be used to split strings, eg. `'1a2b3 4'.split(/[^0-9]/)==['1', '2', '3', '4']`. */ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) { if (!jsvIsString(parent)) return 0; JsVar *array = jsvNewEmptyArray(); if (!array) return 0; // out of memory if (jsvIsUndefined(split)) { jsvArrayPush(array, parent); return array; } #ifndef SAVE_ON_FLASH // Use RegExp if one is passed in if (jsvIsInstanceOf(split, "RegExp")) { unsigned int last = 0; JsVar *match; jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0)); match = jswrap_regexp_exec(split, parent); while (match && !jsvIsNull(match)) { // get info about match JsVar *matchStr = jsvGetArrayItem(match,0); JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0)); JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr); jsvUnLock(matchStr); // do the replacement jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last))); last = idx+len; // search again jsvUnLock(match); jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(last)); match = jswrap_regexp_exec(split, parent); } jsvUnLock(match); jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0)); // add remaining string after last match if (last<=jsvGetStringLength(parent)) jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, JSVAPPENDSTRINGVAR_MAXLENGTH)); return array; } #endif split = jsvAsString(split); int idx, last = 0; int splitlen = jsvIsUndefined(split) ? 0 : (int)jsvGetStringLength(split); int l = (int)jsvGetStringLength(parent) + 1 - splitlen; for (idx=0;idx<=l;idx++) { if (splitlen==0 && idx==0) continue; // special case for where split string is "" if (idx==l || splitlen==0 || jsvCompareString(parent, split, (size_t)idx, 0, true)==0) { if (idx==l) { idx=l+splitlen; // if the last element, do to the end of the string if (splitlen==0) break; } JsVar *part = jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last)); if (!part) break; // out of memory jsvArrayPush(array, part); jsvUnLock(part); last = idx+splitlen; } } jsvUnLock(split); return array; }
/*JSON{ "type" : "method", "class" : "String", "name" : "replace", "generate" : "jswrap_string_replace", "params" : [ ["subStr","JsVar","The string to search for"], ["newSubStr","JsVar","The string to replace it with"] ], "return" : ["JsVar","This string with `subStr` replaced"] } Search and replace ONE occurrance of `subStr` with `newSubStr` and return the result. This doesn't alter the original string. Regular expressions not supported. */ JsVar *jswrap_string_replace(JsVar *parent, JsVar *subStr, JsVar *newSubStr) { JsVar *str = jsvAsString(parent); #ifndef SAVE_ON_FLASH // Use RegExp if one is passed in if (jsvIsInstanceOf(subStr, "RegExp")) { JsVar *replace; if (jsvIsFunction(newSubStr) || jsvIsString(newSubStr)) replace = jsvLockAgain(newSubStr); else replace = jsvAsString(newSubStr); jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); bool global = jswrap_regexp_hasFlag(subStr,'g'); JsVar *match; match = jswrap_regexp_exec(subStr, str); while (match && !jsvIsNull(match) && !jspIsInterrupted()) { // get info about match JsVar *matchStr = jsvGetArrayItem(match,0); JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0)); JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr); // do the replacement JsVar *newStr = jsvNewFromStringVar(str, 0, (size_t)idx); JsvStringIterator dst; jsvStringIteratorNew(&dst, newStr, 0); jsvStringIteratorGotoEnd(&dst); if (jsvIsFunction(replace)) { unsigned int argCount = 0; JsVar *args[13]; args[argCount++] = jsvLockAgain(matchStr); JsVar *v; while ((v = jsvGetArrayItem(match, (JsVarInt)argCount))) args[argCount++] = v; args[argCount++] = jsvObjectGetChild(match,"index",0); args[argCount++] = jsvObjectGetChild(match,"input",0); JsVar *result = jsvAsStringAndUnLock(jspeFunctionCall(replace, 0, 0, false, (JsVarInt)argCount, args)); jsvUnLockMany(argCount, args); jsvStringIteratorAppendString(&dst, result, 0); jsvUnLock(result); } else { JsvStringIterator src; jsvStringIteratorNew(&src, replace, 0); while (jsvStringIteratorHasChar(&src)) { char ch = jsvStringIteratorGetChar(&src); if (ch=='$') { jsvStringIteratorNext(&src); ch = jsvStringIteratorGetChar(&src); JsVar *group = 0; if (ch>'0' && ch<='9') group = jsvGetArrayItem(match, ch-'0'); if (group) { jsvStringIteratorAppendString(&dst, group, 0); jsvUnLock(group); } else { jsvStringIteratorAppend(&dst, '$'); jsvStringIteratorAppend(&dst, ch); } } else { jsvStringIteratorAppend(&dst, ch); } jsvStringIteratorNext(&src); } jsvStringIteratorFree(&src); } JsVarInt lastIndex = 1+(JsVarInt)jsvStringIteratorGetIndex(&dst); jsvStringIteratorAppendString(&dst, str, (size_t)(idx+len)); jsvStringIteratorFree(&dst); jsvUnLock2(str,matchStr); str = newStr; // search again if global jsvUnLock(match); match = 0; if (global) { jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(lastIndex)); match = jswrap_regexp_exec(subStr, str); } } jsvUnLock(match); jsvUnLock(replace); // reset lastIndex if global if (global) jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); return str; } #endif newSubStr = jsvAsString(newSubStr); subStr = jsvAsString(subStr); int idx = jswrap_string_indexOf(parent, subStr, 0, false); if (idx>=0) { JsVar *newStr = jsvNewFromStringVar(str, 0, (size_t)idx); jsvAppendStringVar(newStr, newSubStr, 0, JSVAPPENDSTRINGVAR_MAXLENGTH); jsvAppendStringVar(newStr, str, (size_t)idx+jsvGetStringLength(subStr), JSVAPPENDSTRINGVAR_MAXLENGTH); jsvUnLock(str); str = newStr; } jsvUnLock2(subStr, newSubStr); return str; }