/*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" : "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; }
/*JSON{ "type" : "method", "class" : "String", "name" : "split", "generate" : "jswrap_string_split", "params" : [ ["separator","JsVar","The start character index"] ], "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]``` */ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) { JsVar *array = jsvNewEmptyArray(); if (!array) return 0; // out of memory if (jsvIsUndefined(split)) { jsvArrayPush(array, parent); return array; } split = jsvAsString(split, false); 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" : "Pin", "name" : "getInfo", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_pin_getInfo", "return" : ["JsVar","An object containing information about this pins"] } Get information about this pin and its capabilities. Of the form: ``` { "port" : "A", // the Pin's port on the chip "num" : 12, // the Pin's number "in_addr" : 0x..., // (if available) the address of the pin's input address in bit-banded memory (can be used with peek) "out_addr" : 0x..., // (if available) the address of the pin's output address in bit-banded memory (can be used with poke) "analog" : { ADCs : [1], channel : 12 }, // If analog input is available "functions" : { "TIM1":{type:"CH1, af:0}, "I2C3":{type:"SCL", af:1} } } ``` Will return undefined if pin is not valid. */ JsVar *jswrap_pin_getInfo( JsVar *parent //!< The class instance representing the pin. ) { Pin pin = jshGetPinFromVar(parent); if (!jshIsPinValid(pin)) return 0; const JshPinInfo *inf = &pinInfo[pin]; JsVar *obj = jsvNewObject(); if (!obj) return 0; char buf[2]; buf[0] = (char)('A'+(inf->port-JSH_PORTA)); buf[1] = 0; jsvObjectSetChildAndUnLock(obj, "port", jsvNewFromString(buf)); jsvObjectSetChildAndUnLock(obj, "num", jsvNewFromInteger(inf->pin-JSH_PIN0)); #ifdef STM32 volatile uint32_t *addr; addr = jshGetPinAddress(pin, JSGPAF_INPUT); if (addr) jsvObjectSetChildAndUnLock(obj, "in_addr", jsvNewFromInteger((JsVarInt)addr)); addr = jshGetPinAddress(pin, JSGPAF_OUTPUT); if (addr) jsvObjectSetChildAndUnLock(obj, "out_addr", jsvNewFromInteger((JsVarInt)addr)); #endif // ADC if (inf->analog) { JsVar *an = jsvNewObject(); if (an) { JsVar *arr = jsvNewEmptyArray(); if (arr) { int i; for (i=0; i<ADC_COUNT; i++) if (inf->analog&(JSH_ANALOG1<<i)) jsvArrayPushAndUnLock(arr, jsvNewFromInteger(1+i)); jsvObjectSetChildAndUnLock(an, "ADCs", arr); } jsvObjectSetChildAndUnLock(obj, "channel", jsvNewFromInteger(inf->analog & JSH_MASK_ANALOG_CH)); } } JsVar *funcs = jsvNewObject(); if (funcs) { int i; for (i=0; i<JSH_PININFO_FUNCTIONS; i++) { if (inf->functions[i]) { JsVar *func = jsvNewObject(); if (func) { char buf[16]; jshPinFunctionToString(inf->functions[i], JSPFTS_TYPE, buf, sizeof(buf)); jsvObjectSetChildAndUnLock(func, "type", jsvNewFromString(buf)); jsvObjectSetChildAndUnLock(func, "af", jsvNewFromInteger(inf->functions[i] & JSH_MASK_AF)); jshPinFunctionToString(inf->functions[i], JSPFTS_DEVICE|JSPFTS_DEVICE_NUMBER, buf, sizeof(buf)); jsvObjectSetChildAndUnLock(funcs, buf, func); } } } jsvObjectSetChildAndUnLock(obj, "functions", funcs); } return obj; }
JsVar *jswrap_object_keys_or_property_names( JsVar *obj, bool includeNonEnumerable, ///< include 'hidden' items bool includePrototype ///< include items for the prototype too (for autocomplete) ) { JsVar *arr = jsvNewEmptyArray(); if (!arr) return 0; jswrap_object_keys_or_property_names_cb(obj, includeNonEnumerable, includePrototype, (void (*)(void *, JsVar *))jsvArrayAddUnique, arr); return arr; }
/*JSON{ "type" : "method", "class" : "Array", "name" : "shift", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_array_shift", "params" : [ ], "return" : ["JsVar","The element that was removed"] } Remove and return the first element of the array. This is the opposite of `[1,2,3].pop()`, which takes an element off the end. */ JsVar *jswrap_array_shift(JsVar *parent) { // just use splice, as this does all the hard work for us JsVar *nRemove = jsvNewFromInteger(1); JsVar *elements = jsvNewEmptyArray(); JsVar *arr = jswrap_array_splice(parent, 0, nRemove, elements); jsvUnLock2(elements, nRemove); // unpack element from the array JsVar *el = 0; if (jsvIsArray(arr)) el = jsvArrayPop(arr); jsvUnLock(arr); return el; }
/*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); } }
static JsVar *matchfound(JsvStringIterator *txtIt, matchInfo info) { JsVar *rmatch = jsvNewEmptyArray(); size_t endIndex = jsvStringIteratorGetIndex(txtIt); JsVar *matchStr = jsvNewFromStringVar(info.sourceStr, info.startIndex, endIndex-info.startIndex); jsvSetArrayItem(rmatch, 0, matchStr); jsvUnLock(matchStr); int i; for (i=0;i<info.groups;i++) { matchStr = jsvNewFromStringVar(info.sourceStr, info.groupStart[i], info.groupEnd[i]-info.groupStart[i]); jsvSetArrayItem(rmatch, i+1, matchStr); jsvUnLock(matchStr); } jsvObjectSetChildAndUnLock(rmatch, "index", jsvNewFromInteger((JsVarInt)info.startIndex)); jsvObjectSetChild(rmatch, "input", info.sourceStr); return rmatch; }
/*JSON{ "type" : "method", "class" : "Array", "name" : "slice", "generate" : "jswrap_array_slice", "params" : [ ["start","int","Start index"], ["end","JsVar","End index (optional)"] ], "return" : ["JsVar","A new array"] } Return a copy of a portion of this array (in a new array) */ JsVar *jswrap_array_slice(JsVar *parent, JsVarInt start, JsVar *endVar) { JsVarInt len = jsvGetLength(parent); JsVarInt end = len; if (!jsvIsUndefined(endVar)) end = jsvGetInteger(endVar); JsVarInt k = 0; JsVarInt final = len; JsVar *array = jsvNewEmptyArray(); if (!array) return 0; if (start<0) k = max((len + start), 0); else k = min(start, len); if (end<0) final = max((len + end), 0); else final = min(end, len);
/*JSON{ "type" : "constructor", "class" : "Array", "name" : "Array", "generate" : "jswrap_array_constructor", "params" : [ ["args","JsVarArray","The length of the array OR any number of items to add to the array"] ], "return" : ["JsVar","An Array"] } Create an Array. Either give it one integer argument (>=0) which is the length of the array, or any number of arguments */ JsVar *jswrap_array_constructor(JsVar *args) { assert(args); if (jsvGetArrayLength(args)==1) { JsVar *firstArg = jsvSkipNameAndUnLock(jsvGetArrayItem(args,0)); if (jsvIsNumeric(firstArg)) { JsVarFloat f = jsvGetFloat(firstArg); JsVarInt count = jsvGetInteger(firstArg); jsvUnLock(firstArg); if (f!=count || count<0) { jsExceptionHere(JSET_ERROR, "Invalid array length"); return 0; } else { JsVar *arr = jsvNewEmptyArray(); if (!arr) return 0; // out of memory jsvSetArrayLength(arr, count, false); return arr; } } else { jsvUnLock(firstArg); } } // Otherwise, we just return the array! return jsvLockAgain(args); }
JsVar *jswrap_json_parse_internal() { switch (lex->tk) { case LEX_R_TRUE: jslGetNextToken(lex); return jsvNewFromBool(true); case LEX_R_FALSE: jslGetNextToken(lex); return jsvNewFromBool(false); case LEX_R_NULL: jslGetNextToken(lex); return jsvNewWithFlags(JSV_NULL); case '-': { jslGetNextToken(lex); if (lex->tk!=LEX_INT && lex->tk!=LEX_FLOAT) return 0; JsVar *v = jswrap_json_parse_internal(lex); JsVar *zero = jsvNewFromInteger(0); JsVar *r = jsvMathsOp(zero, v, '-'); jsvUnLock2(v, zero); return r; } case LEX_INT: { long long v = stringToInt(jslGetTokenValueAsString(lex)); jslGetNextToken(lex); return jsvNewFromLongInteger(v); } case LEX_FLOAT: { JsVarFloat v = stringToFloat(jslGetTokenValueAsString(lex)); jslGetNextToken(lex); return jsvNewFromFloat(v); } case LEX_STR: { JsVar *a = jslGetTokenValueAsVar(lex); jslGetNextToken(lex); return a; } case '[': { JsVar *arr = jsvNewEmptyArray(); if (!arr) return 0; jslGetNextToken(lex); // [ while (lex->tk != ']' && !jspHasError()) { JsVar *value = jswrap_json_parse_internal(lex); if (!value || (lex->tk!=']' && !jslMatch(','))) { jsvUnLock2(value, arr); return 0; } jsvArrayPush(arr, value); jsvUnLock(value); } if (!jslMatch(']')) { jsvUnLock(arr); return 0; } return arr; } case '{': { JsVar *obj = jsvNewObject(); if (!obj) return 0; jslGetNextToken(lex); // { while (lex->tk == LEX_STR && !jspHasError()) { JsVar *key = jsvAsArrayIndexAndUnLock(jslGetTokenValueAsVar(lex)); jslGetNextToken(lex); JsVar *value = 0; if (!jslMatch(':') || !(value=jswrap_json_parse_internal(lex)) || (lex->tk!='}' && !jslMatch(','))) { jsvUnLock3(key, value, obj); return 0; } jsvAddName(obj, jsvMakeIntoVariableName(key, value)); jsvUnLock2(value, key); } if (!jslMatch('}')) { jsvUnLock(obj); return 0; } return obj; } default: { char buf[32]; jslTokenAsString(lex->tk, buf, 32); jsExceptionHere(JSET_SYNTAXERROR, "Expecting a valid value, got %s", buf); return 0; // undefined = error } } }
/*JSON{ "type" : "method", "class" : "Array", "name" : "splice", "generate" : "jswrap_array_splice", "params" : [ ["index","int","Index at which to start changing the array. If negative, will begin that many elements from the end"], ["howMany","JsVar","An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed."], ["elements","JsVarArray","One or more items to add to the array"] ], "return" : ["JsVar","An array containing the removed elements. If only one element is removed, an array of one element is returned."] } Both remove and add items to an array */ JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *elements) { if (!jsvIsArray(parent)) return 0; JsVarInt len = jsvGetArrayLength(parent); if (index<0) index+=len; if (index<0) index=0; if (index>len) index=len; JsVarInt howMany = len; // how many to delete! if (jsvIsInt(howManyVar)) howMany = jsvGetInteger(howManyVar); if (howMany > len-index) howMany = len-index; JsVarInt newItems = jsvGetArrayLength(elements); JsVarInt shift = newItems-howMany; bool needToAdd = false; JsVar *result = jsvNewEmptyArray(); JsvObjectIterator it; jsvObjectIteratorNew(&it, parent); while (jsvObjectIteratorHasValue(&it) && !needToAdd) { bool goToNext = true; JsVar *idxVar = jsvObjectIteratorGetKey(&it); if (idxVar && jsvIsInt(idxVar)) { JsVarInt idx = jsvGetInteger(idxVar); if (idx<index) { // do nothing... } else if (idx<index+howMany) { // must delete if (result) { // append to result array JsVar *el = jsvObjectIteratorGetValue(&it); jsvArrayPushAndUnLock(result, el); } // delete goToNext = false; JsVar *toRemove = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); jsvRemoveChild(parent, toRemove); jsvUnLock(toRemove); } else { // we're greater than the amount we need to remove now needToAdd = true; goToNext = false; } } jsvUnLock(idxVar); if (goToNext) jsvObjectIteratorNext(&it); } // now we add everything JsVar *beforeIndex = jsvObjectIteratorGetKey(&it); JsvObjectIterator itElement; jsvObjectIteratorNew(&itElement, elements); while (jsvObjectIteratorHasValue(&itElement)) { JsVar *element = jsvObjectIteratorGetValue(&itElement); jsvArrayInsertBefore(parent, beforeIndex, element); jsvUnLock(element); jsvObjectIteratorNext(&itElement); } jsvObjectIteratorFree(&itElement); jsvUnLock(beforeIndex); // And finally renumber while (jsvObjectIteratorHasValue(&it)) { JsVar *idxVar = jsvObjectIteratorGetKey(&it); if (idxVar && jsvIsInt(idxVar)) { jsvSetInteger(idxVar, jsvGetInteger(idxVar)+shift); } jsvUnLock(idxVar); jsvObjectIteratorNext(&it); } // free jsvObjectIteratorFree(&it); // and reset array size jsvSetArrayLength(parent, len + shift, false); return result; }
JsVar *_jswrap_array_iterate_with_callback(const char *name, JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool wantArray, bool isBoolCallback, bool expectedValue) { if (!jsvIsIterable(parent)) { jsExceptionHere(JSET_ERROR, "Array.%s can only be called on something iterable", name); return 0; } if (!jsvIsFunction(funcVar)) { jsExceptionHere(JSET_ERROR, "Array.%s's first argument should be a function", name); return 0; } if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) { jsExceptionHere(JSET_ERROR, "Array.%s's second argument should be undefined, or an object", name); return 0; } JsVar *result = 0; if (wantArray) result = jsvNewEmptyArray(); bool isDone = false; if (result || !wantArray) { JsvIterator it; jsvIteratorNew(&it, parent); while (jsvIteratorHasElement(&it) && !isDone) { JsVar *index = jsvIteratorGetKey(&it); if (jsvIsInt(index)) { JsVarInt idxValue = jsvGetInteger(index); JsVar *args[3], *cb_result; args[0] = jsvIteratorGetValue(&it); args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index args[2] = parent; cb_result = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args); jsvUnLockMany(2,args); if (cb_result) { bool matched; if (isBoolCallback) matched = (jsvGetBool(cb_result) == expectedValue); if (wantArray) { if (isBoolCallback) { // filter if (matched) { jsvArrayPushAndUnLock(result, jsvIteratorGetValue(&it)); } } else { // map JsVar *name = jsvNewFromInteger(idxValue); if (name) { // out of memory? jsvMakeIntoVariableName(name, cb_result); jsvAddName(result, name); jsvUnLock(name); } } } else { // break the loop early if expecting a particular value and didn't get it if (isBoolCallback && !matched) isDone = true; } jsvUnLock(cb_result); } } jsvUnLock(index); jsvIteratorNext(&it); } jsvIteratorFree(&it); } /* boolean result depends on whether the loop terminated early for 'some' or completed for 'every' */ if (!wantArray && isBoolCallback) { result = jsvNewFromBool(isDone != expectedValue); } return result; }
/*JSON{ "type" : "method", "class" : "OneWire", "name" : "search", "generate" : "jswrap_onewire_search", "params" : [ ["command","int32","(Optional) command byte. If not specified (or zero), this defaults to 0xF0. This can could be set to 0xEC to perform a DS18B20 'Alarm Search Command'"] ], "return" : ["JsVar","An array of devices that were found"] } Search for devices */ JsVar *jswrap_onewire_search(JsVar *parent, int command) { // search - code from http://www.maximintegrated.com/app-notes/index.mvp/id/187 Pin pin = onewire_getpin(parent); if (!jshIsPinValid(pin)) return 0; JsVar *array = jsvNewEmptyArray(); if (!array) return 0; if (command<=0 || command>255) command = 0xF0; // normal search command // global search state unsigned char ROM_NO[8]; int LastDiscrepancy; int LastFamilyDiscrepancy; int LastDeviceFlag; // reset the search state LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; int search_result = true; while (search_result) { int id_bit_number; int last_zero, rom_byte_number; unsigned char id_bit, cmp_id_bit; unsigned char rom_byte_mask, search_direction; // initialize for search id_bit_number = 1; last_zero = 0; rom_byte_number = 0; rom_byte_mask = 1; search_result = 0; // if the last call was not the last one if (!LastDeviceFlag) { // 1-Wire reset if (!OneWireReset(pin)) { // reset the search LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; return array; } // issue the search command OneWireWrite(pin, 8, (unsigned long long)command); // loop to do the search do { // read a bit and its complement id_bit = (unsigned char)OneWireRead(pin, 1); cmp_id_bit = (unsigned char)OneWireRead(pin, 1); // check for no devices on 1-wire if ((id_bit == 1) && (cmp_id_bit == 1)) break; else { // all devices coupled have 0 or 1 if (id_bit != cmp_id_bit) search_direction = id_bit; // bit write value for search else { // if this discrepancy if before the Last Discrepancy // on a previous next then pick the same as last time if (id_bit_number < LastDiscrepancy) search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); else // if equal to last pick 1, if not then pick 0 search_direction = (id_bit_number == LastDiscrepancy); // if 0 was picked then record its position in LastZero if (search_direction == 0) { last_zero = id_bit_number; // check for Last discrepancy in family if (last_zero < 9) LastFamilyDiscrepancy = last_zero; } } // set or clear the bit in the ROM byte rom_byte_number // with mask rom_byte_mask if (search_direction == 1) ROM_NO[rom_byte_number] |= rom_byte_mask; else ROM_NO[rom_byte_number] &= (unsigned char)~rom_byte_mask; // serial number search direction write bit OneWireWrite(pin, 1, search_direction); // increment the byte counter id_bit_number // and shift the mask rom_byte_mask id_bit_number++; rom_byte_mask = (unsigned char)(rom_byte_mask << 1); // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask if (rom_byte_mask == 0) { rom_byte_number++; rom_byte_mask = 1; } } } while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 // if the search was successful then if (!((id_bit_number < 65))) { // search successful so set LastDiscrepancy,LastDeviceFlag,search_result LastDiscrepancy = last_zero; // check for last device if (LastDiscrepancy == 0) LastDeviceFlag = TRUE; search_result = TRUE; } } // if no device found then reset counters so next 'search' will be like a first if (!search_result || !ROM_NO[0]) { LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; search_result = FALSE; } if (search_result) { int i; char buf[17]; for (i=0;i<8;i++) { buf[i*2] = itoch((ROM_NO[i]>>4) & 15); buf[i*2+1] = itoch(ROM_NO[i] & 15); } buf[16]=0; jsvArrayPushAndUnLock(array, jsvNewFromString(buf)); } NOT_USED(LastFamilyDiscrepancy); } return array; }
/*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; }
/** Call a function with the given argument specifiers */ JsVar *jsnCallFunction(void *function, JsnArgumentType argumentSpecifier, JsVar *thisParam, JsVar **paramData, int paramCount) { #ifndef SAVE_ON_FLASH // Handle common call types quickly: // ------- void(void) if (argumentSpecifier==JSWAT_VOID) { ((void (*)())function)(); return 0; } // ------- JsVar*(void) if (argumentSpecifier==JSWAT_JSVAR) { return ((JsVar *(*)())function)(); } // ------- void('this') if (argumentSpecifier==(JSWAT_VOID | JSWAT_THIS_ARG)) { ((void (*)(JsVar *))function)(thisParam); return 0; } #endif // Now do it the hard way... JsnArgumentType returnType = (JsnArgumentType)(argumentSpecifier&JSWAT_MASK); JsVar *argsArray = 0; // if JSWAT_ARGUMENT_ARRAY is ever used (note it'll only ever be used once) int paramNumber = 0; // how many parameters we have int argCount = 0; size_t argData[MAX_ARGS]; #ifdef USE_SEPARATE_DOUBLES int doubleCount = 0; JsVarFloat doubleData[MAX_ARGS]; #endif // prepend the 'this' link if we need one if (argumentSpecifier&JSWAT_THIS_ARG) argData[argCount++] = (size_t)thisParam; argumentSpecifier = (argumentSpecifier & JSWAT_ARGUMENTS_MASK) >> JSWAT_BITS; #ifdef USE_ARG_REORDERING size_t alignedLongsAfter = 0; #endif // run through all arguments while (argumentSpecifier & JSWAT_MASK) { // Get the parameter data JsVar *param = (paramNumber<paramCount) ? paramData[paramNumber] : (JsVar *)0; paramNumber++; // try and pack it: JsnArgumentType argType = (JsnArgumentType)(argumentSpecifier&JSWAT_MASK); #ifdef USE_ARG_REORDERING if (!JSWAT_IS_64BIT(argType) && !(argCount&1)) { argCount += alignedLongsAfter*2; alignedLongsAfter = 0; } #endif if (argCount > MAX_ARGS - (JSWAT_IS_64BIT(argType)?2:1)) { // TODO: can we ever hit this because of JsnArgumentType's restrictions? jsError("INTERNAL: too many arguments for jsnCallFunction"); } switch (argType) { case JSWAT_JSVAR: { // standard variable argData[argCount++] = (size_t)param; break; } case JSWAT_ARGUMENT_ARRAY: { // a JsVar array containing all subsequent arguments argsArray = jsvNewEmptyArray(); if (argsArray) { // push everything into the array while (paramNumber<=paramCount) { jsvArrayPush(argsArray, param); param = (paramNumber<paramCount) ? paramData[paramNumber] : 0; paramNumber++; } } // push the array argData[argCount++] = (size_t)argsArray; break; } case JSWAT_BOOL: // boolean argData[argCount++] = jsvGetBool(param); break; case JSWAT_INT32: // 32 bit int argData[argCount++] = (uint32_t)jsvGetInteger(param); break; case JSWAT_PIN: // 16 bit int argData[argCount++] = (uint32_t)jshGetPinFromVar(param); break; case JSWAT_JSVARFLOAT: { // 64 bit float JsVarFloat f = jsvGetFloat(param); #ifdef USE_SEPARATE_DOUBLES doubleData[doubleCount++] = f; #else uint64_t i = *(uint64_t*)&f; #if USE_64BIT argData[argCount++] = (size_t)i; #else // 32 bit... #ifdef USE_ARG_REORDERING if (argCount&1) { size_t argC = argCount+1; argData[argC++] = (size_t)((i) & 0xFFFFFFFF); argData[argC++] = (size_t)((i>>32) & 0xFFFFFFFF); alignedLongsAfter++; } else { argData[argCount++] = (size_t)((i) & 0xFFFFFFFF); argData[argCount++] = (size_t)((i>>32) & 0xFFFFFFFF); } #else // no reordering if (argCount&1) argCount++; argData[argCount++] = (size_t)((i) & 0xFFFFFFFF); argData[argCount++] = (size_t)((i>>32) & 0xFFFFFFFF); #endif #endif #endif break; } default: assert(0); break; }