/*JSON{ "type" : "staticmethod", "class" : "Promise", "name" : "all", "generate" : "jswrap_promise_all", "params" : [ ["promises","JsVar","An array of promises"] ], "return" : ["JsVar","A new Promise"] } Return a new promise that is resolved when all promises in the supplied array are resolved. */ JsVar *jswrap_promise_all(JsVar *arr) { if (!jsvIsIterable(arr)) { jsExceptionHere(JSET_TYPEERROR, "Expecting something iterable, got %t", arr); return 0; } JsVar *promise = jspNewObject(0, "Promise"); if (!promise) return 0; JsVar *resolve = jsvNewNativeFunction((void (*)(void))jswrap_promise_all_resolve, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS)); JsVar *reject = jsvNewNativeFunction((void (*)(void))jswrap_promise_all_reject, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS)); if (resolve && reject) { jsvObjectSetChild(resolve, JSPARSE_FUNCTION_THIS_NAME, promise); jsvObjectSetChild(reject, JSPARSE_FUNCTION_THIS_NAME, promise); int promises = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { JsVar *p = jsvObjectIteratorGetValue(&it); jsvUnLock(jswrap_promise_then(p, resolve)); jsvUnLock(jswrap_promise_catch(p, reject)); jsvUnLock(p); promises++; jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvObjectSetChildAndUnLock(promise, JS_PROMISE_COUNT_NAME, jsvNewFromInteger(promises)); jsvObjectSetChildAndUnLock(promise, JS_PROMISE_RESULT_NAME, jsvNewEmptyArray()); } jsvUnLock2(resolve, reject); return promise; }
/** A convenience function for adding event listeners */ void jswrap_object_addEventListener(JsVar *parent, const char *eventName, void (*callback)(), JsnArgumentType argTypes) { JsVar *n = jsvNewFromString(eventName); JsVar *cb = jsvNewNativeFunction(callback, argTypes); jswrap_object_on(parent, n, cb); jsvUnLock(cb); jsvUnLock(n); }
void _jswrap_promise_queuereject(JsVar *promise, JsVar *data) { JsVar *fn = jsvNewNativeFunction((void (*)(void))_jswrap_promise_reject, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS)); if (!fn) return; jsvObjectSetChild(fn, JSPARSE_FUNCTION_THIS_NAME, promise); jsiQueueEvents(promise, fn, &data, 1); jsvUnLock(fn); }
/*JSON{ "type" : "constructor", "class" : "Promise", "name" : "Promise", "generate" : "jswrap_promise_constructor", "params" : [ ["executor","JsVar","A function of the form `function (resolve, reject)`"] ], "return" : ["JsVar","A Promise"] } Create a new Promise. The executor function is executed immediately (before the constructor even returns) and */ JsVar *jswrap_promise_constructor(JsVar *executor) { JsVar *obj = jspNewObject(0, "Promise"); if (obj) { // create resolve and reject JsVar *args[2] = { jsvNewNativeFunction((void (*)(void))_jswrap_promise_queueresolve, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS)), jsvNewNativeFunction((void (*)(void))_jswrap_promise_queuereject, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS)) }; // bind 'this' to functions if (args[0]) jsvObjectSetChild(args[0], JSPARSE_FUNCTION_THIS_NAME, obj); if (args[1]) jsvObjectSetChild(args[1], JSPARSE_FUNCTION_THIS_NAME, obj); // call the executor jsvUnLock(jspeFunctionCall(executor, 0, obj, false, 2, args)); jsvUnLockMany(2, args); } return obj; }
/*JSON{ "type" : "function", "name" : "require", "generate" : "jswrap_require", "params" : [ ["moduleName","JsVar","A String containing the name of the given module"] ], "return" : ["JsVar","The result of evaluating the string"] } Load the given module, and return the exported functions */ JsVar *jswrap_require(JsVar *moduleName) { if (!jsvIsString(moduleName)) { jsWarn("Expecting a module name as a string, but got %t", moduleName); return 0; } // Search to see if we have already loaded this module JsVar *moduleList = jswrap_modules_getModuleList(); if (!moduleList) return 0; // out of memory JsVar *moduleExportName = jsvFindChildFromVar(moduleList, moduleName, true); jsvUnLock(moduleList); if (!moduleExportName) return 0; // out of memory JsVar *moduleExport = jsvSkipName(moduleExportName); if (moduleExport) { // Found the module! jsvUnLock(moduleExportName); return moduleExport; } // Now check if it is built-in char moduleNameBuf[32]; jsvGetString(moduleName, moduleNameBuf, sizeof(moduleNameBuf)); void *builtInLib = jswGetBuiltInLibrary(moduleNameBuf); if (builtInLib) { // create a 'fake' module that Espruino can use to map its built-in functions against moduleExport = jsvNewNativeFunction(builtInLib, 0); } else { // Now try and load it JsVar *fileContents = 0; //if (jsvIsStringEqual(moduleName,"http")) {} //if (jsvIsStringEqual(moduleName,"fs")) {} #ifdef USE_FILESYSTEM JsVar *modulePath = jsvNewFromString("node_modules/"); if (!modulePath) { jsvUnLock(moduleExportName); return 0; } // out of memory jsvAppendStringVarComplete(modulePath, moduleName); jsvAppendString(modulePath,".js"); fileContents = jswrap_fs_readFile(modulePath); jsvUnLock(modulePath); #endif if (!fileContents || jsvIsStringEqual(fileContents,"")) { jsvUnLock(moduleExportName); jsvUnLock(fileContents); jsWarn("Module %q not found", moduleName); return 0; } moduleExport = jspEvaluateModule(fileContents); jsvUnLock(fileContents); } if (moduleExport) // could have been out of memory jsvSetValueOfName(moduleExportName, moduleExport); // save in cache jsvUnLock(moduleExportName); return moduleExport; }
/*JSON{ "type" : "staticmethod", "ifndef" : "SAVE_ON_FLASH", "class" : "E", "name" : "nativeCall", "generate" : "jswrap_espruino_nativeCall", "params" : [ ["addr","int","The address in memory of the function"], ["sig","JsVar","The signature of the call, `returnType (arg1,arg2,...)`. Allowed types are `void`,`bool`,`int`,`double`,`Pin`,`JsVar`"] ], "return" : ["JsVar","The native function"] } ADVANCED: This is a great way to crash Espruino if you're not sure what you are doing Create a native function that executes the code at the given address. Eg. `E.nativeCall(0x08012345,'double (double,double)')(1.1, 2.2)` If you're executing a thumb function, you'll almost certainly need to set the bottom bit of the address to 1. Note it's not guaranteed that the call signature you provide can be used - it has to be something that a function in Espruino already uses. */ JsVar *jswrap_espruino_nativeCall(JsVarInt addr, JsVar *signature) { unsigned int argTypes = 0; if (jsvIsUndefined(signature)) { // Nothing to do } else if (jsvIsString(signature)) { JsLex lex; jslInit(&lex, signature); int argType; bool ok = true; int argNumber = 0; argType = nativeCallGetCType(&lex); if (argType>=0) argTypes |= (unsigned)argType << (JSWAT_BITS * argNumber++); else ok = false; if (ok) ok = jslMatch(&lex, '('); while (ok && lex.tk!=LEX_EOF && lex.tk!=')') { argType = nativeCallGetCType(&lex); if (argType>=0) { argTypes |= (unsigned)argType << (JSWAT_BITS * argNumber++); if (lex.tk!=')') ok = jslMatch(&lex, ','); } else ok = false; } if (ok) ok = jslMatch(&lex, ')'); jslKill(&lex); if (argTypes & (unsigned int)~0xFFFF) ok = false; if (!ok) { jsExceptionHere(JSET_ERROR, "Error Parsing signature at argument number %d", argNumber); return 0; } } else { jsExceptionHere(JSET_ERROR, "Invalid Signature"); return 0; } return jsvNewNativeFunction((void *)(size_t)addr, (unsigned short)argTypes); }
/*JSON{ "type" : "method", "class" : "Function", "name" : "bind", "generate" : "jswrap_function_bind", "params" : [ ["this","JsVar","The value to use as the 'this' argument when executing the function"], ["params","JsVarArray","Optional Default parameters that are prepended to the call"] ], "return" : ["JsVar","The 'bound' function"] } This executes the function with the supplied 'this' argument and parameters */ JsVar *jswrap_function_bind(JsVar *parent, JsVar *thisArg, JsVar *argsArray) { if (!jsvIsFunction(parent)) { jsExceptionHere(JSET_TYPEERROR, "Function.bind expects to be called on function, got %t", parent); return 0; } JsVar *fn; if (jsvIsNativeFunction(parent)) fn = jsvNewNativeFunction(parent->varData.native.ptr, parent->varData.native.argTypes); else fn = jsvNewWithFlags(jsvIsFunctionReturn(parent) ? JSV_FUNCTION_RETURN : JSV_FUNCTION); if (!fn) return 0; // Old function info JsvObjectIterator fnIt; jsvObjectIteratorNew(&fnIt, parent); // add previously bound arguments while (jsvObjectIteratorHasValue(&fnIt)) { JsVar *param = jsvObjectIteratorGetKey(&fnIt); JsVar *defaultValue = jsvObjectIteratorGetValue(&fnIt); bool wasBound = jsvIsFunctionParameter(param) && defaultValue; if (wasBound) { JsVar *newParam = jsvCopy(param); if (newParam) { // could be out of memory jsvAddName(fn, newParam); jsvUnLock(newParam); } } jsvUnLock2(param, defaultValue); if (!wasBound) break; jsvObjectIteratorNext(&fnIt); } // add bound arguments JsvObjectIterator argIt; jsvObjectIteratorNew(&argIt, argsArray); while (jsvObjectIteratorHasValue(&argIt)) { JsVar *defaultValue = jsvObjectIteratorGetValue(&argIt); bool addedParam = false; while (!addedParam && jsvObjectIteratorHasValue(&fnIt)) { JsVar *param = jsvObjectIteratorGetKey(&fnIt); if (!jsvIsFunctionParameter(param)) { jsvUnLock(param); break; } JsVar *newParam = jsvCopyNameOnly(param, false, true); jsvSetValueOfName(newParam, defaultValue); jsvAddName(fn, newParam); addedParam = true; jsvUnLock2(param, newParam); jsvObjectIteratorNext(&fnIt); } if (!addedParam) { JsVar *paramName = jsvNewFromEmptyString(); if (paramName) { jsvMakeFunctionParameter(paramName); // force this to be called a function parameter jsvSetValueOfName(paramName, defaultValue); jsvAddName(fn, paramName); jsvUnLock(paramName); } } jsvUnLock(defaultValue); jsvObjectIteratorNext(&argIt); } jsvObjectIteratorFree(&argIt); // Copy the rest of the old function's info while (jsvObjectIteratorHasValue(&fnIt)) { JsVar *param = jsvObjectIteratorGetKey(&fnIt); JsVar *newParam = jsvCopyNameOnly(param, true, true); if (newParam) { // could be out of memory jsvAddName(fn, newParam); jsvUnLock(newParam); } jsvUnLock(param); jsvObjectIteratorNext(&fnIt); } jsvObjectIteratorFree(&fnIt); // Add 'this' jsvObjectSetChild(fn, JSPARSE_FUNCTION_THIS_NAME, thisArg); // no unlock needed return fn; }
void addNativeFunction(const char *name, void (*callbackPtr)(void)) { jsvUnLock(jsvObjectSetChild(execInfo.root, name, jsvNewNativeFunction(callbackPtr, JSWAT_VOID))); }
/*JSON{ "type" : "init", "generate" : "jswrap_wice_init" }*/ void jswrap_wice_init() { jspCallNamedFunction(execInfo.root, "USB.setConsole", 0, 0); jspEvaluate("USB.setConsole();"); #ifdef WICE_DEBUG WDEBUGLN("USB is console"); #endif /*JsVar *mode = jsvNewFromString("output"); jswrap_io_pinMode(jshGetPinFromString(PIN_DASH7_XTAL_EN), mode); jswrap_io_pinMode(jshGetPinFromString(PIN_DASH7_RST), mode); jsvUnLock(mode);*/ enableDASH(); // Set up the DASH7 USART how we want it JshUSARTInfo inf; jshUSARTInitInfo(&inf); inf.baudRate = 115200; inf.pinRX = jshGetPinFromString(PIN_DASH7_RX); inf.pinTX = jshGetPinFromString(PIN_DASH7_TX); jshUSARTSetup(EV_SERIAL1, &inf); JsVar *serial = jspGetNamedField(execInfo.root, SERIAL1_DASH7, false); jswrap_object_addEventListener(serial, "data", dash7Callback, JSWAT_VOID | (JSWAT_JSVAR<<(JSWAT_BITS))); jsvUnLock(serial); startTime = jshGetSystemTime(); wice_msg_init(&wifiMessage, wifiMessageBuffer, 2048); wice_msg_init(&dash7Message, dash7MessageBuffer, 256); options = jspEvaluate("x = {\"repeat\": \"true\", \"edge\": \"rising\", \"debounce\":\"50\"}"); Pin btn = jshGetPinFromString("B10"); JsVar *btnmode = jsvNewFromString("input"); jswrap_io_pinMode(btn, btnmode); jsvUnLock(btnmode); #ifdef GATEWAY WDEBUGLN("GATEWAY"); blink(PIN_GRN, 50); /// opendrain and digitalwrite 1 will 'opencircuit it' /// http://www.espruino.com/Reference#l__global_pinMode JsVar *opendrain = jsvNewFromString("opendrain"); WDEBUGSTRVAR(opendrain); jswrap_io_pinMode(jshGetPinFromString(PIN_ESP_GPIO_0), opendrain); jswrap_io_pinMode(jshGetPinFromString(PIN_ESP_GPIO_2), opendrain); jshPinOutput(jshGetPinFromString(PIN_ESP_GPIO_0), 1); jshPinOutput(jshGetPinFromString(PIN_ESP_GPIO_2), 1); jsvUnLock(opendrain); /// must opendrain gpio0/2 because of boot modes /// https://github.com/esp8266/esp8266-wiki/wiki/Boot-Process enableWifi(); // Set up the Wifi USART how we want it JshUSARTInfo inf4; jshUSARTInitInfo(&inf4); inf4.baudRate = 115200; inf4.pinRX = jshGetPinFromString(PIN_ESP_RX); inf4.pinTX = jshGetPinFromString(PIN_ESP_TX); jshUSARTSetup(EV_SERIAL4, &inf4); /// make button restart wifi for gateway JsVar *restartWifi_fn = jsvNewNativeFunction(restartWifi, JSWAT_VOID); btnEvent = jswrap_interface_setWatch(restartWifi_fn, btn, options); jsvUnLock(restartWifi_fn); /// configure wifi usart callback JsVar *wifiSerial = jspGetNamedField(execInfo.root, SERIAL4_WIFI, false); jswrap_object_addEventListener(wifiSerial, "data", wifiCallback, JSWAT_VOID | (JSWAT_JSVAR<<(JSWAT_BITS))); jsvUnLock(wifiSerial); doSendSerial(); #else WDEBUGLN("NODE"); blink(PIN_BLUE, 50); /// make button a forced measurement for nodes JsVar *doMeasurementAndWaitForResponse_fn = jsvNewNativeFunction(doMeasurementAndWaitForResponse, JSWAT_VOID); btnEvent = jswrap_interface_setWatch(doMeasurementAndWaitForResponse_fn, btn, options); jsvUnLock(doMeasurementAndWaitForResponse_fn); /// set up main interval callback for nodes JsVar *doMeasurement_fn = jsvNewNativeFunction(doMeasurement, JSWAT_VOID); currentInterval = jswrap_interface_setInterval(doMeasurement_fn, INTERVAL, 0); jsvUnLock(doMeasurement_fn); /// prepare the I2C bus for talking with the Si7050 temp sensor JsVar *s = jspEvaluate("I2C1.setup({scl:B8, sda:B9, bitrate:50000});"); jsvUnLock(s); disableDASH(); jswrap_interface_setDeepSleep(true); //do deep sleep [TODO can we wake on press?] #endif }