/*JSON{ "type" : "method", "class" : "Object", "name" : "removeListener", "generate" : "jswrap_object_removeListener", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to remove"] ] } Removes the specified event listener. ``` function foo(d) { console.log(d); } Serial1.on("data", foo); Serial1.removeListener("data", foo); ``` */ void jswrap_object_removeListener(JsVar *parent, JsVar *event, JsVar *callback) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (jsvIsString(event)) { // remove the whole child containing listeners JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventListName = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); JsVar *eventList = jsvSkipName(eventListName); if (eventList) { if (eventList == callback) { // there's no array, it was a single item jsvRemoveChild(parent, eventListName); } else if (jsvIsArray(eventList)) { // it's an array, search for the index JsVar *idx = jsvGetArrayIndexOf(eventList, callback, true); if (idx) { jsvRemoveChild(eventList, idx); jsvUnLock(idx); } } jsvUnLock(eventList); } jsvUnLock(eventListName); } else { jsWarn("First argument to EventEmitter.removeListener(..) must be a string"); return; } }
/*JSON{ "type" : "method", "class" : "Object", "name" : "emit", "generate" : "jswrap_object_emit", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["args","JsVarArray","Optional arguments"] ] } Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter. */ void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *argArray) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.emit(..) must be a string"); return; } char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); // extract data const int MAX_ARGS = 4; JsVar *args[MAX_ARGS]; int n = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, argArray); while (jsvObjectIteratorHasValue(&it)) { if (n>=MAX_ARGS) { jsWarn("Too many arguments"); break; } args[n++] = jsvObjectIteratorGetValue(&it); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsiQueueObjectCallbacks(parent, eventName, args, n); // unlock while (n--) jsvUnLock(args[n]); }
esp_err_t registerCallbacks(){ esp_err_t ret; ret = esp_ble_gap_register_callback(gap_event_handler);if (ret){jsWarn("gap register error:%x\n", ret);return ret;} ret = esp_ble_gatts_register_callback(gatts_event_handler);if(ret){jsWarn("gatts register error:%x\n", ret);return ret;} ret = esp_ble_gattc_register_callback(gattc_event_handler);if(ret){jsWarn("gattc regigister error:%x\n",ret);return ret;} return ret; }
/*JSON{ "type" : "staticmethod", "class" : "Trig", "name" : "setTrigger", "generate" : "jswrap_trig_setTrigger", "params" : [ ["num","int","The trigger number (0..7)"], ["pos","float","The position (in degrees) to fire the trigger at"], ["pins","JsVar","An array of pins to pulse (max 4)"], ["pulseLength","float","The time (in msec) to pulse for"] ] } Set a trigger for a certain point in the cycle */ void jswrap_trig_setTrigger(JsVarInt num, JsVarFloat position, JsVar *pins, JsVarFloat pulseLength) { TriggerStruct *trig = &mainTrigger; if (num<0 || num>=TRIGGER_TRIGGERS_COUNT) { jsWarn("Invalid trigger number\n"); return; } if (!jsvIsArray(pins)) { jsWarn("Second argument must be an array of pins\n"); return; } if (jsvGetArrayLength(pins) > TRIGGERPOINT_TRIGGERS_COUNT) { jsWarn("Too many pins in array\n"); return; } // convert from degrees to teeth position = wrapAround(((position - trig->keyPosition) * trig->teethTotal / 360), trig->teethTotal); TriggerPointStruct *tp = &trig->triggers[num]; tp->newTooth = (unsigned char)position; tp->newToothFraction = (unsigned char)((position - tp->tooth)*256); tp->pulseLength = jshGetTimeFromMilliseconds(pulseLength); int i, l=(int)jsvGetArrayLength(pins); for (i=0;i<TRIGGERPOINT_TRIGGERS_COUNT;i++) { tp->pins[i] = (Pin)((i<l) ? jshGetPinFromVarAndUnLock(jsvGetArrayItem(pins, i)) : PIN_UNDEFINED); } // now copy over data if we need to do it immediately if (tp->tooth==TRIGGERPOINT_TOOTH_DISABLE || tp->newTooth==TRIGGERPOINT_TOOTH_DISABLE) { tp->tooth = tp->newTooth; tp->toothFraction = tp->newToothFraction; } // all done! }
esp_err_t initController(){ esp_err_t ret; esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); ret = esp_bt_controller_init(&bt_cfg);if(ret) {jsWarn("init controller failed:%x\n",ret); return ret;} ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);if(ret) {jsWarn("enable controller failed:%x\n",ret); return ret;} return ret; }
/*JSON{ "type" : "method", "class" : "Object", "name" : "emit", "generate" : "jswrap_object_emit", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["args","JsVarArray","Optional arguments"] ] } Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter. */ void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *argArray) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.emit(..) must be a string"); return; } char eventName[16]; if (!jswrap_object_get_event_name(eventName, event)) return; // extract data const unsigned int MAX_ARGS = 4; JsVar *args[MAX_ARGS]; unsigned int n = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, argArray); while (jsvObjectIteratorHasValue(&it)) { if (n>=MAX_ARGS) { jsWarn("Too many arguments"); break; } args[n++] = jsvObjectIteratorGetValue(&it); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsiQueueObjectCallbacks(parent, eventName, args, (int)n); // unlock jsvUnLockMany(n, args); }
/*JSON{ "type" : "method", "class" : "Object", "name" : "removeAllListeners", "generate" : "jswrap_object_removeAllListeners", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"] ] } Removes all listeners, or those of the specified event. */ void jswrap_object_removeAllListeners(JsVar *parent, JsVar *event) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (jsvIsString(event)) { // remove the whole child containing listeners JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventList = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); if (eventList) { jsvRemoveChild(parent, eventList); jsvUnLock(eventList); } } else if (jsvIsUndefined(event)) { // Eep. We must remove everything beginning with '#on' (JS_EVENT_PREFIX) JsvObjectIterator it; jsvObjectIteratorNew(&it, parent); while (jsvObjectIteratorHasValue(&it)) { JsVar *key = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (jsvIsStringEqualOrStartsWith(key, JS_EVENT_PREFIX, true)) { // begins with #on - we must kill it jsvRemoveChild(parent, key); } jsvUnLock(key); } jsvObjectIteratorFree(&it); } else { jsWarn("First argument to EventEmitter.removeAllListeners(..) must be a string, or undefined"); return; } }
/*JSON{ "type":"function", "name" : "require", "description" : "Load the given module, and return the exported functions", "generate" : "jswrap_require", "params" : [ [ "moduleName", "JsVar", "A String containing the name of the given module"] ], "return" : ["JsVar", "The result of evaluating the string"] }*/ 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)); if (jswIsBuiltInLibrary(moduleNameBuf)) { // create a 'fake' module that Espruino can use to map its built-in functions against moduleExport = jspNewBuiltin(moduleNameBuf); } else { // Now try and load it JsVar *fileContents = 0; //if (jsvIsStringEqual(moduleName,"http")) {} //if (jsvIsStringEqual(moduleName,"fs")) {} #ifdef USE_FILESYSTEM JsVar *modulePath = jsvNewFromString( #ifdef LINUX "node_modules/" #else "NODE_M~1/" #endif ); if (!modulePath) { jsvUnLock(moduleExportName); return 0; } // out of memory jsvAppendStringVarComplete(modulePath, moduleName); jsvAppendString(modulePath,".js"); fileContents = wrap_fat_readFile(modulePath); jsvUnLock(modulePath); #endif if (!fileContents || jsvIsStringEqual(fileContents,"")) { jsvUnLock(moduleExportName); jsvUnLock(fileContents); jsWarn("Module not found"); return 0; } moduleExport = jspEvaluateModule(jsiGetParser(), fileContents); jsvUnLock(fileContents); } assert(moduleExport); jsvSetValueOfName(moduleExportName, moduleExport); // save in cache jsvUnLock(moduleExportName); return moduleExport; }
/*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "pipe", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_pipe", "params" : [ ["source","JsVar","The source file/stream that will send content."], ["destination","JsVar","The destination file/stream that will receive content from the source."], ["options","JsVar",["An optional object `{ chunkSize : int=64, end : bool=true, complete : function }`","chunkSize : The amount of data to pipe from source to destination at a time","complete : a function to call when the pipe activity is complete","end : call the 'end' function on the destination when the source is finished"]] ] }*/ void jswrap_pipe(JsVar* source, JsVar* dest, JsVar* options) { if (!source || !dest) return; JsVar *pipe = jspNewObject(0, "Pipe"); JsVar *arr = pipeGetArray(true); JsVar* position = jsvNewFromInteger(0); if (pipe && arr && position) {// out of memory? JsVar *readFunc = jspGetNamedField(source, "read", false); JsVar *writeFunc = jspGetNamedField(dest, "write", false); if(jsvIsFunction(readFunc)) { if(jsvIsFunction(writeFunc)) { JsVarInt chunkSize = 64; bool callEnd = true; // parse Options Object if (jsvIsObject(options)) { JsVar *c; c = jsvObjectGetChild(options, "complete", false); if (c) { jsvObjectSetChild(pipe, "#oncomplete", c); jsvUnLock(c); } c = jsvObjectGetChild(options, "end", false); if (c) callEnd = jsvGetBoolAndUnLock(c); c = jsvObjectGetChild(options, "chunkSize", false); if (c) { if (jsvIsNumeric(c) && jsvGetInteger(c)>0) chunkSize = jsvGetInteger(c); else jsWarn("chunkSize must be an integer > 0"); jsvUnLock(c); } } else if (!jsvIsUndefined(options)) { jsWarn("'options' must be an object, or undefined"); } // set up our event listeners jswrap_object_addEventListener(source, "close", jswrap_pipe_src_close_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1))); jswrap_object_addEventListener(dest, "drain", jswrap_pipe_drain_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1))); jswrap_object_addEventListener(dest, "close", jswrap_pipe_dst_close_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1))); // set up the rest of the pipe jsvUnLock(jsvObjectSetChild(pipe, "chunkSize", jsvNewFromInteger(chunkSize))); jsvUnLock(jsvObjectSetChild(pipe, "end", jsvNewFromBool(callEnd))); jsvUnLock(jsvAddNamedChild(pipe, position, "position")); jsvUnLock(jsvAddNamedChild(pipe, source, "source")); jsvUnLock(jsvAddNamedChild(pipe, dest, "destination")); // add the pipe to our list jsvArrayPush(arr, pipe); } else { jsExceptionHere(JSET_ERROR, "Destination object does not implement the required write(buffer, length, position) method."); } } else { jsExceptionHere(JSET_ERROR, "Source object does not implement the required read(buffer, length, position) method."); } jsvUnLock(readFunc); jsvUnLock(writeFunc); } jsvUnLock(arr); jsvUnLock(pipe); jsvUnLock(position); }
/*JSON{ "type":"method", "class": "Object", "name" : "emit", "description" : ["Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter."], "generate" : "jswrap_object_emit", "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"], [ "v1", "JsVar", "Optional argument 1"], [ "v2", "JsVar", "Optional argument 2"] ] }*/ void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *v1, JsVar *v2) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.emit(..) must be a string"); return; } char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); jsiQueueObjectCallbacks(parent, eventName, v1, v2); }
/*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" : "method", "class" : "Object", "name" : "on", "generate" : "jswrap_object_on", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to call when this event is received"] ] } Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter. */ void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.on(..) must be a string"); return; } if (!jsvIsFunction(listener) && !jsvIsString(listener)) { jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); return; } JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventList = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); JsVar *eventListeners = jsvSkipName(eventList); if (jsvIsUndefined(eventListeners)) { // just add jsvSetValueOfName(eventList, listener); } else { if (jsvIsArray(eventListeners)) { // we already have an array, just add to it jsvArrayPush(eventListeners, listener); } else { // not an array - we need to make it an array JsVar *arr = jsvNewEmptyArray(); jsvArrayPush(arr, eventListeners); jsvArrayPush(arr, listener); jsvSetValueOfName(eventList, arr); jsvUnLock(arr); } } jsvUnLock2(eventListeners, eventList); /* Special case if we're a data listener and data has already arrived then * we queue an event immediately. */ if (jsvIsStringEqual(event, "data")) { JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0); if (jsvIsString(buf)) { jsiQueueObjectCallbacks(parent, STREAM_CALLBACK_NAME, &buf, 1); jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME); } jsvUnLock(buf); } }
/*JSON{ "type" : "method", "class" : "OneWire", "name" : "select", "generate" : "jswrap_onewire_select", "params" : [ ["rom","JsVar","The device to select (get this using `OneWire.search()`)"] ] } Select a ROM - reset needs to be done first */ void jswrap_onewire_select(JsVar *parent, JsVar *rom) { Pin pin = onewire_getpin(parent); if (!jshIsPinValid(pin)) return; if (!jsvIsString(rom) || jsvGetStringLength(rom)!=16) { jsWarn("Invalid OneWire device address"); return; } // decode the address unsigned long long romdata = 0; JsvStringIterator it; jsvStringIteratorNew(&it, rom, 0); int i; for (i=0;i<8;i++) { char b[3]; b[0] = jsvStringIteratorGetChar(&it); jsvStringIteratorNext(&it); b[1] = jsvStringIteratorGetChar(&it); jsvStringIteratorNext(&it); b[2] = 0; romdata = romdata | (((unsigned long long)stringToIntWithRadix(b,16,0)) << (i*8)); } jsvStringIteratorFree(&it); // finally write data out OneWireWrite(pin, 8, 0x55); OneWireWrite(pin, 64, romdata); }
/*JSON{ "type" : "constructor", "class" : "Date", "name" : "Date", "generate" : "jswrap_date_constructor", "params" : [ ["args","JsVarArray","Either nothing (current time), one numeric argument (milliseconds since 1970), a date string (see `Date.parse`), or [year, month, day, hour, minute, second, millisecond] "] ], "return" : ["JsVar","A Date object"], "return_object" : "Date" } Creates a date object */ JsVar *jswrap_date_constructor(JsVar *args) { JsVarFloat time = 0; if (jsvGetArrayLength(args)==0) { time = jswrap_date_now(); } else if (jsvGetArrayLength(args)==1) { JsVar *arg = jsvGetArrayItem(args, 0); if (jsvIsNumeric(arg)) time = jsvGetFloat(arg); else if (jsvIsString(arg)) time = jswrap_date_parse(arg); else jsWarn("Variables of type %t are not supported in date constructor", arg); jsvUnLock(arg); } else { CalendarDate date; date.year = (int)jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 0)); date.month = (int)jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 1)); date.day = (int)jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 2)); TimeInDay td; td.daysSinceEpoch = fromCalenderDate(&date); td.hour = (int)jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 3)); td.min = (int)jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 4)); td.sec = (int)jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 5)); td.ms = (int)jsvGetIntegerAndUnLock(jsvGetArrayItem(args, 6)); td.zone = 0; time = fromTimeInDay(&td); } return jswrap_date_from_milliseconds(time); }
/*JSON{ "type":"method", "class": "Function", "name" : "apply", "description" : ["This executes the function with the supplied 'this' argument and parameters"], "generate" : "jswrap_function_apply", "params" : [ [ "this", "JsVar", "The value to use as the 'this' argument when executing the function"], [ "args", "JsVar", "Optional Array of Aruments"] ], "return" : [ "JsVar", "The return value of executing this function" ] }*/ JsVar *jswrap_function_apply(JsVar *parent, JsVar *thisArg, JsVar *argsArray) { unsigned int i; JsVar **args = 0; size_t argC = 0; if (jsvIsArray(argsArray)) { argC = (size_t)jsvGetArrayLength(argsArray); if (argC>64) argC=64; // sanity args = (JsVar**)alloca((size_t)argC * sizeof(JsVar*)); for (i=0;i<argC;i++) args[i] = 0; JsvArrayIterator it; jsvArrayIteratorNew(&it, argsArray); while (jsvArrayIteratorHasElement(&it)) { JsVarInt idx = jsvGetIntegerAndUnLock(jsvArrayIteratorGetIndex(&it)); if (idx>=0 && idx<(int)argC) { assert(!args[idx]); // just in case there were dups args[idx] = jsvArrayIteratorGetElement(&it); } jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); } else if (!jsvIsUndefined(argsArray)) { jsWarn("Second argument to Function.apply must be an array"); } JsVar *r = jspeFunctionCall(parent, 0, thisArg, false, (int)argC, args); for (i=0;i<argC;i++) jsvUnLock(args[i]); return r; }
/*JSON{ "type":"method", "class" : "Ethernet", "name" : "setIP", "generate" : "jswrap_ethernet_setIP", "description" : "Set the current IP address for get an IP from DHCP (if no options object is specified)", "params" : [ [ "options", "JsVar", "Object containing IP address options `{ ip : '1,2,3,4', subnet, gateway, dns }`, or do not supply an object in otder to force DHCP."] ], "return" : ["bool", "True on success"] }*/ bool jswrap_ethernet_setIP(JsVar *wlanObj, JsVar *options) { NOT_USED(wlanObj); if (networkState != NETWORKSTATE_ONLINE) { jsError("Not connected to the internet"); return false; } bool success = false; wiz_NetInfo gWIZNETINFO; ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO); if (jsvIsObject(options)) { _eth_getIP_set_address(options, "ip", &gWIZNETINFO.ip[0]); _eth_getIP_set_address(options, "subnet", &gWIZNETINFO.sn[0]); _eth_getIP_set_address(options, "gateway", &gWIZNETINFO.gw[0]); _eth_getIP_set_address(options, "dns", &gWIZNETINFO.dns[0]); gWIZNETINFO.dhcp = NETINFO_STATIC; success = true; } else { // DHCP uint8_t DHCPisSuccess = getIP_DHCPS(net_wiznet_getFreeSocket(), &gWIZNETINFO); if (DHCPisSuccess == 1) { // info in lease_time.lVal success = true; } else { jsWarn("DHCP failed"); success = false; } } ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO); return success; }
/*JSON{ "type" : "staticmethod", "class" : "Trig", "name" : "getTrigger", "generate" : "jswrap_trig_getTrigger", "params" : [ ["num","int","The trigger number (0..7)"] ], "return" : ["JsVar","A structure containing all information about the trigger"] } Get the current state of a trigger */ JsVar *jswrap_trig_getTrigger(JsVarInt num) { TriggerStruct *trig = &mainTrigger; if (num<0 || num>=TRIGGER_TRIGGERS_COUNT) { jsWarn("Invalid trigger number\n"); return 0; } TriggerPointStruct *tp = &trig->triggers[num]; // get offset in teeth JsVarFloat position = tp->tooth + (tp->toothFraction/256.0); // convert from teeth to degrees position = wrapAround((position * 360 / trig->teethTotal) + trig->keyPosition, 360); JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0; JsVar *v; v = jsvNewFromFloat(position); jsvUnLock(jsvAddNamedChild(obj, v, "pos")); jsvUnLock(v); v = jsvNewFromFloat(jshGetMillisecondsFromTime(tp->pulseLength)); jsvUnLock(jsvAddNamedChild(obj, v, "pulseLength")); jsvUnLock(v); v = jsvNewWithFlags(JSV_ARRAY); int i; if (v) { for (i=0;i<TRIGGERPOINT_TRIGGERS_COUNT;i++) if (tp->pins[i] != PIN_UNDEFINED) { jsvArrayPushAndUnLock(v, jsvNewFromPin(tp->pins[i])); } } jsvUnLock(jsvAddNamedChild(obj, v, "pins")); jsvUnLock(v); return obj; }
void jsWarnUUID(esp_bt_uuid_t char_uuid){ if (char_uuid.len == ESP_UUID_LEN_16) { jsWarn("- - - Char UUID16: %x", char_uuid.uuid.uuid16); } else if (char_uuid.len == ESP_UUID_LEN_32) { jsWarn("- - - Char UUID32: %x", char_uuid.uuid.uuid32); } else if (char_uuid.len == ESP_UUID_LEN_128) { jsWarn("- - - Char UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_uuid.uuid.uuid128[0], char_uuid.uuid.uuid128[1], char_uuid.uuid.uuid128[2], char_uuid.uuid.uuid128[3], char_uuid.uuid.uuid128[4], char_uuid.uuid.uuid128[5], char_uuid.uuid.uuid128[6], char_uuid.uuid.uuid128[7], char_uuid.uuid.uuid128[8], char_uuid.uuid.uuid128[9], char_uuid.uuid.uuid128[10], char_uuid.uuid.uuid128[11], char_uuid.uuid.uuid128[12], char_uuid.uuid.uuid128[13], char_uuid.uuid.uuid128[14], char_uuid.uuid.uuid128[15]); } else { jsWarn("- - - Char UNKNOWN LEN %d\n", char_uuid.len); } }
/*JSON{ "type":"staticmethod", "class": "Object", "name" : "keys", "description" : "Return all enumerable keys of the given object", "generate" : "jswrap_object_keys", "params" : [ [ "object", "JsVar", "The object to return keys for"] ], "return" : ["JsVar", "An array of strings - one for each key on the given object"] }*/ JsVar *jswrap_object_keys(JsVar *obj) { if (jsvIsIterable(obj)) { bool (*checkerFunction)(JsVar*) = 0; if (jsvIsFunction(obj)) checkerFunction = jsvIsInternalFunctionKey; else if (jsvIsObject(obj)) checkerFunction = jsvIsInternalObjectKey; JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; JsvIterator it; jsvIteratorNew(&it, obj); while (jsvIteratorHasElement(&it)) { JsVar *key = jsvIteratorGetKey(&it); if (!(checkerFunction && checkerFunction(key))) { JsVar *name = jsvCopyNameOnly(key,false,false); if (name) { jsvArrayPushAndUnLock(arr, name); } } jsvUnLock(key); jsvIteratorNext(&it); } jsvIteratorFree(&it); return arr; } else { jsWarn("Object.keys called on non-object"); return 0; } }
/*JSON{ "type":"method", "class": "Function", "name" : "replaceWith", "description" : ["This replaces the function with the one in the argument - while keeping the old function's scope. This allows inner functions to be edited, and is used when edit() is called on an inner function."], "generate" : "jswrap_function_replaceWith", "params" : [ [ "newFunc", "JsVar", "The new function to replace this function with"] ] }*/ void jswrap_function_replaceWith(JsVar *oldFunc, JsVar *newFunc) { if (!jsvIsFunction(newFunc)) { jsWarn("First argument of replaceWith should be a function - ignoring"); return; } // Grab scope - the one thing we want to keep JsVar *scope = jsvFindChildFromString(oldFunc, JSPARSE_FUNCTION_SCOPE_NAME, false); // so now remove all existing entries jsvRemoveAllChildren(oldFunc); // now re-add scope jsvAddName(oldFunc, scope); jsvUnLock(scope); // now re-add other entries JsObjectIterator it; jsvObjectIteratorNew(&it, newFunc); while (jsvObjectIteratorHasElement(&it)) { JsVar *el = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (!jsvIsStringEqual(el, JSPARSE_FUNCTION_SCOPE_NAME)) { JsVar *copy = jsvCopy(el); if (copy) { jsvAddName(oldFunc, copy); jsvUnLock(copy); } } } jsvObjectIteratorFree(&it); }
/*JSON{ "type" : "method", "class" : "Object", "name" : "on", "generate" : "jswrap_object_on", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to call when this event is received"] ] } Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter. */ void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.on(..) must be a string"); return; } if (!jsvIsFunction(listener) && !jsvIsString(listener)) { jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); return; } char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); JsVar *eventList = jsvFindChildFromString(parent, eventName, true); JsVar *eventListeners = jsvSkipName(eventList); if (jsvIsUndefined(eventListeners)) { // just add jsvSetValueOfName(eventList, listener); } else { if (jsvIsArray(eventListeners)) { // we already have an array, just add to it jsvArrayPush(eventListeners, listener); } else { // not an array - we need to make it an array JsVar *arr = jsvNewWithFlags(JSV_ARRAY); jsvArrayPush(arr, eventListeners); jsvArrayPush(arr, listener); jsvSetValueOfName(eventList, arr); jsvUnLock(arr); } } jsvUnLock(eventListeners); jsvUnLock(eventList); /* Special case if we're a data listener and data has already arrived then * we queue an event immediately. */ if (jsvIsStringEqual(event, "data")) { JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0); if (jsvIsString(buf)) { jsiQueueObjectCallbacks(parent, "#ondata", &buf, 1); jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME); } jsvUnLock(buf); } }
/*JSON{ "type":"function", "name" : "digitalPulse", "description" : ["Pulse the pin with the value for the given time in milliseconds", "eg. ```pulse(A0,1,500);``` pulses A0 high for 500ms" ], "generate" : "jswrap_io_digitalPulse", "params" : [ [ "pin", "pin", "The pin to use"], [ "value", "bool", "Whether to pulse high (true) or low (false)"], [ "time", "float", "A time in milliseconds"] ] }*/ void jswrap_io_digitalPulse(Pin pin, bool value, JsVarFloat time) { if (time<=0) { jsWarn("Pulse Time given for digitalPulse is less that or equal to 0"); } else { //jsPrintInt((JsVarInt)(time*1000)); jshPinPulse(pin, value, time); } }
/*JSON{ "type":"function", "name" : "digitalPulse", "description" : ["Pulse the pin with the value for the given time in milliseconds. It uses a hardware timer to produce accurate pulses, and returns immediately (before the pulse has finished). Use `digitalPulse(A0,1,0)` to wait until a previous pulse has finished.", "eg. `digitalPulse(A0,1,5);` pulses A0 high for 5ms", "digitalPulse is for SHORT pulses that need to be very accurate. If you're doing anything over a few milliseconds, use setTimeout instead." ], "generate" : "jswrap_io_digitalPulse", "params" : [ [ "pin", "pin", "The pin to use"], [ "value", "bool", "Whether to pulse high (true) or low (false)"], [ "time", "float", "A time in milliseconds"] ] }*/ void jswrap_io_digitalPulse(Pin pin, bool value, JsVarFloat time) { if (time<0 || isnan(time)) { jsWarn("Pulse Time given for digitalPulse is less than 0, or not a number"); } else { //jsPrintInt((JsVarInt)(time*1000)); jshPinPulse(pin, value, time); } }
// This is for Object.keys and Object. JsVar *jswrap_object_keys_or_property_names(JsVar *obj, bool includeNonEnumerable) { // strings are iterable, but we shouldn't try and show keys for them if (jsvIsIterable(obj) && !jsvIsString(obj)) { JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(obj); JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; JsvIterator it; jsvIteratorNew(&it, obj); while (jsvIteratorHasElement(&it)) { JsVar *key = jsvIteratorGetKey(&it); if (!(checkerFunction && checkerFunction(key)) || (jsvIsStringEqual(key, JSPARSE_CONSTRUCTOR_VAR))) { /* Not sure why constructor is included in getOwnPropertyNames, but * not in for (i in ...) but it is, so we must explicitly override the * check in jsvIsInternalObjectKey! */ JsVar *name = jsvAsArrayIndexAndUnLock(jsvCopyNameOnly(key, false, false)); if (name) { jsvArrayPushAndUnLock(arr, name); } } jsvUnLock(key); jsvIteratorNext(&it); } jsvIteratorFree(&it); /* Search our built-in symbol table Assume that ALL builtins are non-enumerable. This isn't great but seems to work quite well right now! */ if (includeNonEnumerable) { const JswSymList *symbols = 0; JsVar *protoOwner = jspGetPrototypeOwner(obj); if (protoOwner) { symbols = jswGetSymbolListForObjectProto(protoOwner); jsvUnLock(protoOwner); } else if (!jsvIsObject(obj)) { // get symbols, but only if we're not doing it on a basic object symbols = jswGetSymbolListForObject(obj); } if (symbols) { unsigned int i; for (i=0;i<symbols->symbolCount;i++) jsvArrayAddString(arr, &symbols->symbolChars[symbols->symbols[i].strOffset]); } if (jsvIsArray(obj) || jsvIsString(obj)) { jsvArrayAddString(arr, "length"); } } return arr; } else { jsWarn("Object.keys called on non-object"); return 0; } }
/*JSON{ "type" : "constructor", "class" : "Pin", "name" : "Pin", "generate" : "jswrap_pin_constructor", "params" : [ ["value", "JsVar", "A value to be converted to a pin. Can be a number, pin, or String."] ], "return" : ["JsVar","A Pin object"] } Creates a pin from the given argument (or returns undefined if no argument) */ JsVar *jswrap_pin_constructor(JsVar *val) { Pin pin = jshGetPinFromVar(val); if (!jshIsPinValid(pin)) return 0; #ifdef ESP8266 if (jsvIsInt(val) && !jsvIsPin(val)) jsWarn("The Pin() constructor is deprecated. Please use `D%d`, or NodeMCU.Dx instead", pin); #endif return jsvNewFromPin(pin); }
/** Iterate over the contents of var, calling callback for each. Contents may be: * * numeric -> output * * a string -> output each character * * array/arraybuffer -> call itself on each element * * object -> call itself object.count times, on object.data */ bool jsvIterateCallback(JsVar *data, void (*callback)(int item, void *callbackData), void *callbackData) { bool ok = true; if (jsvIsNumeric(data)) { callback((int)jsvGetInteger(data), callbackData); } else if (jsvIsObject(data)) { JsVar *countVar = jsvObjectGetChild(data, "count", 0); JsVar *dataVar = jsvObjectGetChild(data, "data", 0); if (countVar && dataVar && jsvIsNumeric(countVar)) { int n = (int)jsvGetInteger(countVar); while (ok && n-- > 0) { ok = jsvIterateCallback(dataVar, callback, callbackData); } } else { jsWarn("If specifying an object, it must be of the form {data : ..., count : N}"); } jsvUnLock(countVar); jsvUnLock(dataVar); } else if (jsvIsString(data)) { JsvStringIterator it; jsvStringIteratorNew(&it, data, 0); while (jsvStringIteratorHasChar(&it) && ok) { char ch = jsvStringIteratorGetChar(&it); callback(ch, callbackData); jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); } else if (jsvIsIterable(data)) { JsvIterator it; jsvIteratorNew(&it, data); while (jsvIteratorHasElement(&it) && ok) { JsVar *el = jsvIteratorGetValue(&it); ok = jsvIterateCallback(el, callback, callbackData); jsvUnLock(el); jsvIteratorNext(&it); } jsvIteratorFree(&it); } else { jsWarn("Expecting a number or something iterable, got %t", data); ok = false; } return ok; }
/*JSON{ "type" : "staticmethod", "class" : "Trig", "name" : "killTrigger", "generate" : "jswrap_trig_killTrigger", "params" : [ ["num","int","The trigger number (0..7)"] ] } Disable a trigger */ void jswrap_trig_killTrigger(JsVarInt num) { TriggerStruct *trig = &mainTrigger; if (num<0 || num>=TRIGGER_TRIGGERS_COUNT) { jsWarn("Invalid trigger number\n"); return; } TriggerPointStruct *tp = &trig->triggers[num]; tp->tooth = TRIGGERPOINT_TOOTH_DISABLE; tp->newTooth = TRIGGERPOINT_TOOTH_DISABLE; }
static void jswrap_waveform_start(JsVar *waveform, Pin pin, JsVarFloat freq, JsVar *options, bool isWriting) { bool running = jsvGetBoolAndUnLock(jsvObjectGetChild(waveform, "running", 0)); if (running) { jsExceptionHere(JSET_ERROR, "Waveform is already running"); return; } if (!jshIsPinValid(pin)) { jsExceptionHere(JSET_ERROR, "Invalid pin"); return; } if (!isfinite(freq) || freq<0.001) { jsExceptionHere(JSET_ERROR, "Frequency must be above 0.001Hz"); return; } JsSysTime startTime = jshGetSystemTime(); bool repeat = false; if (jsvIsObject(options)) { JsVarFloat t = jsvGetFloatAndUnLock(jsvObjectGetChild(options, "time", 0)); if (isfinite(t) && t>0) startTime = jshGetTimeFromMilliseconds(t*1000); repeat = jsvGetBoolAndUnLock(jsvObjectGetChild(options, "repeat", 0)); } else if (!jsvIsUndefined(options)) { jsExceptionHere(JSET_ERROR, "Expecting options to be undefined or an Object, not %t", options); } bool is16Bit = false; JsVar *buffer = jswrap_waveform_getBuffer(waveform,0, &is16Bit); JsVar *buffer2 = jswrap_waveform_getBuffer(waveform,1,0); UtilTimerEventType eventType; if (is16Bit) { eventType = isWriting ? UET_WRITE_SHORT : UET_READ_SHORT; } else { eventType = isWriting ? UET_WRITE_BYTE : UET_READ_BYTE; } // And finally set it up if (!jstStartSignal(startTime, jshGetTimeFromMilliseconds(1000.0 / freq), pin, buffer, repeat?(buffer2?buffer2:buffer):0, eventType)) jsWarn("Unable to schedule a timer"); jsvUnLock(buffer); jsvUnLock(buffer2); jsvUnLock(jsvObjectSetChild(waveform, "running", jsvNewFromBool(true))); jsvUnLock(jsvObjectSetChild(waveform, "freq", jsvNewFromFloat(freq))); // Add to our list of active waveforms JsVar *waveforms = jsvObjectGetChild(execInfo.hiddenRoot, JSI_WAVEFORM_NAME, JSV_ARRAY); if (waveforms) { jsvArrayPush(waveforms, waveform); jsvUnLock(waveforms); } }
/*JSON{ "type" : "method", "class" : "File", "name" : "seek", "generate_full" : "jswrap_file_skip_or_seek(parent,nBytes,false)", "params" : [ ["nBytes","int32","is an integer specifying the number of bytes to skip forwards."] ] } Seek to a certain position in the file */ void jswrap_file_skip_or_seek(JsVar* parent, int nBytes, bool is_skip) { if (nBytes<0) { if ( is_skip ) jsWarn("Bytes to skip must be >=0"); else jsWarn("Position to seek to must be >=0"); return; } FRESULT res = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data->mode == FM_READ || file.data->mode == FM_WRITE || file.data->mode == FM_READ_WRITE) { #ifndef LINUX res = (FRESULT)f_lseek(&file.data->handle, (DWORD)(is_skip ? f_tell(&file.data->handle) : 0) + (DWORD)nBytes); #else fseek(file.data->handle, nBytes, is_skip ? SEEK_CUR : SEEK_SET); #endif } } } if (res) jsfsReportError(is_skip?"Unable to skip":"Unable to seek", res); }
/*JSON{ "type":"method", "class": "Object", "name" : "on", "description" : ["Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter."], "generate" : "jswrap_object_on", "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"], [ "listener", "JsVar", "The listener to call when this event is received"] ] }*/ void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.on(..) must be a string"); return; } if (!jsvIsFunction(listener) && !jsvIsString(listener)) { jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); return; } char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); JsVar *eventList = jsvFindChildFromString(parent, eventName, true); JsVar *eventListeners = jsvSkipName(eventList); if (jsvIsUndefined(eventListeners)) { // just add jsvSetValueOfName(eventList, listener); } else { if (jsvIsArray(eventListeners)) { // we already have an array, just add to it jsvArrayPush(eventListeners, listener); } else { // not an array - we need to make it an array JsVar *arr = jsvNewWithFlags(JSV_ARRAY); jsvArrayPush(arr, eventListeners); jsvArrayPush(arr, listener); jsvSetValueOfName(eventList, arr); jsvUnLock(arr); } } jsvUnLock(eventListeners); jsvUnLock(eventList); }