/*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; }
/*JSON{ "type" : "staticmethod", "class" : "Math", "name" : "round", "generate" : "jswrap_math_round", "params" : [ ["x","float","The value to round"] ], "return" : ["JsVar","x, rounded to the nearest integer"] }*/ JsVar *jswrap_math_round(double x) { if (!isfinite(x) || isNegativeZero(x)) return jsvNewFromFloat(x); x += (x<0) ? -0.4999999999 : 0.4999999999; JsVarInt i = (JsVarInt)x; if (i==0 && (x<0)) return jsvNewFromFloat(-0.0); // pass -0 through return jsvNewFromInteger(i); }
/*JSON{ "type" : "constructor", "class" : "Number", "name" : "Number", "generate" : "jswrap_number_constructor", "params" : [ ["value","JsVarArray","A single value to be converted to a number"] ], "return" : ["JsVar","A Number object"] } Creates a number */ JsVar *jswrap_number_constructor(JsVar *args) { if (jsvGetArrayLength(args)==0) return jsvNewFromInteger(0); JsVar *val = jsvGetArrayItem(args, 0); JsVar *result = 0; if (jsvIsArray(val)) { JsVarInt l = jsvGetArrayLength(val); if (l==0) result = jsvNewFromInteger(0); else if (l==1) { JsVar *n = jsvGetArrayItem(val, 0); if (jsvIsString(n) && jsvIsEmptyString(n)) result = jsvNewFromInteger(0); else if (!jsvIsBoolean(n)) result=jsvAsNumber(n); jsvUnLock(n); } // else NaN } else if (jsvIsUndefined(val) || jsvIsObject(val)) result = 0; else { if (jsvIsString(val) && jsvIsEmptyString(val)) { result = jsvNewFromInteger(0); } else result = jsvAsNumber(val); } jsvUnLock(val); if (result) return result; return jsvNewFromFloat(NAN); }
/*JSON{ "type" : "staticmethod", "class" : "process", "name" : "memory", "generate" : "jswrap_process_memory", "return" : ["JsVar","Information about memory usage"] } Run a Garbage Collection pass, and return an object containing information on memory usage. * `free` : Memory that is available to be used (in blocks) * `usage` : Memory that has been used (in blocks) * `total` : Total memory (in blocks) * `history` : Memory used for command history - that is freed if memory is low. Note that this is INCLUDED in the figure for 'free' * `gc` : Memory freed during the GC pass * `gctime` : Time taken for GC pass (in milliseconds) * `stackEndAddress` : (on ARM) the address (that can be used with peek/poke/etc) of the END of the stack. The stack grows down, so unless you do a lot of recursion the bytes above this can be used. * `flash_start` : (on ARM) the address of the start of flash memory (usually `0x8000000`) * `flash_binary_end` : (on ARM) the address in flash memory of the end of Espruino's firmware. * `flash_code_start` : (on ARM) the address in flash memory of pages that store any code that you save with `save()`. * `flash_length` : (on ARM) the amount of flash memory this firmware was built for (in bytes). **Note:** Some STM32 chips actually have more memory than is advertised. Memory units are specified in 'blocks', which are around 16 bytes each (depending on your device). See http://www.espruino.com/Performance for more information. **Note:** To find free areas of flash memory, see `require('Flash').getFree()` */ JsVar *jswrap_process_memory() { JsSysTime time1 = jshGetSystemTime(); int gc = jsvGarbageCollect(); JsSysTime time2 = jshGetSystemTime(); JsVar *obj = jsvNewObject(); if (obj) { unsigned int history = 0; JsVar *historyVar = jsvObjectGetChild(execInfo.hiddenRoot, JSI_HISTORY_NAME, 0); if (historyVar) { history = (unsigned int)jsvCountJsVarsUsed(historyVar); // vars used to store history jsvUnLock(historyVar); } unsigned int usage = jsvGetMemoryUsage() - history; unsigned int total = jsvGetMemoryTotal(); jsvObjectSetChildAndUnLock(obj, "free", jsvNewFromInteger((JsVarInt)(total-usage))); jsvObjectSetChildAndUnLock(obj, "usage", jsvNewFromInteger((JsVarInt)usage)); jsvObjectSetChildAndUnLock(obj, "total", jsvNewFromInteger((JsVarInt)total)); jsvObjectSetChildAndUnLock(obj, "history", jsvNewFromInteger((JsVarInt)history)); jsvObjectSetChildAndUnLock(obj, "gc", jsvNewFromInteger((JsVarInt)gc)); jsvObjectSetChildAndUnLock(obj, "gctime", jsvNewFromFloat(jshGetMillisecondsFromTime(time2-time1))); #ifdef ARM extern uint32_t LINKER_END_VAR; // end of ram used (variables) - should be 'void', but 'int' avoids warnings extern uint32_t LINKER_ETEXT_VAR; // end of flash text (binary) section - should be 'void', but 'int' avoids warnings jsvObjectSetChildAndUnLock(obj, "stackEndAddress", jsvNewFromInteger((JsVarInt)(unsigned int)&LINKER_END_VAR)); jsvObjectSetChildAndUnLock(obj, "flash_start", jsvNewFromInteger((JsVarInt)FLASH_START)); jsvObjectSetChildAndUnLock(obj, "flash_binary_end", jsvNewFromInteger((JsVarInt)(unsigned int)&LINKER_ETEXT_VAR)); jsvObjectSetChildAndUnLock(obj, "flash_code_start", jsvNewFromInteger((JsVarInt)FLASH_SAVED_CODE_START)); jsvObjectSetChildAndUnLock(obj, "flash_length", jsvNewFromInteger((JsVarInt)FLASH_TOTAL)); #endif } return obj; }
JsVar *jsvArrayBufferIteratorGetValue(JsvArrayBufferIterator *it) { if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return 0; char data[8]; jsvArrayBufferIteratorGetValueData(it, data); if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { return jsvNewFromFloat(jsvArrayBufferIteratorDataToFloat(it, data)); } else { return jsvNewFromInteger(jsvArrayBufferIteratorDataToInt(it, data)); } }
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":"function", "name" : "parseInt", "description" : "Convert a string representing a number into an integer", "generate" : "jswrap_parseInt", "params" : [ [ "string", "JsVar", ""], [ "radix", "JsVar", "The Radix of the string (optional)"] ], "return" : ["JsVar", "The integer value of the string (or NaN)"] }*/ JsVar *jswrap_parseInt(JsVar *v, JsVar *radixVar) { int radix = 0/*don't force radix*/; if (jsvIsNumeric(radixVar)) radix = (int)jsvGetInteger(radixVar); char buffer[JS_NUMBER_BUFFER_SIZE]; jsvGetString(v, buffer, JS_NUMBER_BUFFER_SIZE); bool hasError; JsVarInt i = stringToIntWithRadix(buffer, radix, &hasError); if (hasError) return jsvNewFromFloat(NAN); return jsvNewFromInteger(i); }
JsVar *jsvArrayBufferIteratorGetValue(JsvArrayBufferIterator *it) { if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return 0; char data[8]; jsvArrayBufferIteratorGetValueData(it, data); if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { return jsvNewFromFloat(jsvArrayBufferIteratorDataToFloat(it, data)); } else { JsVarInt i = jsvArrayBufferIteratorDataToInt(it, data); if (it->type == ARRAYBUFFERVIEW_UINT32) return jsvNewFromLongInteger((long long)(uint32_t)i); return jsvNewFromInteger(i); } }
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 } } }
JsVar *jswrap_json_parse_internal(JsLex *lex) { 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, '-'); jsvUnLock(v); jsvUnLock(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 = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; jslGetNextToken(lex); // [ while (lex->tk != ']') { JsVar *value = jswrap_json_parse_internal(lex); if (!value || (lex->tk!=']' && !jslMatch(lex, ','))) { jsvUnLock(value); jsvUnLock(arr); return 0; } jsvArrayPush(arr, value); jsvUnLock(value); } if (!jslMatch(lex, ']')) { jsvUnLock(arr); return 0; } return arr; } case '{': { JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0; jslGetNextToken(lex); // { while (lex->tk == LEX_STR) { JsVar *key = jsvAsArrayIndexAndUnLock(jslGetTokenValueAsVar(lex)); jslGetNextToken(lex); JsVar *value = 0; if (!jslMatch(lex, ':') || !(value=jswrap_json_parse_internal(lex)) || (lex->tk!='}' && !jslMatch(lex, ','))) { jsvUnLock(key); jsvUnLock(value); jsvUnLock(obj); return 0; } jsvAddName(obj, jsvMakeIntoVariableName(key, value)); jsvUnLock(value); jsvUnLock(key); } if (!jslMatch(lex, '}')) { jsvUnLock(obj); return 0; } return obj; } default: return 0; // undefined = error } }
JsVar *jswrap_date_from_milliseconds(JsVarFloat time) { JsVar *d = jspNewObject(0,"Date"); if (!d) return 0; jsvUnLock(jsvObjectSetChild(d, "ms", jsvNewFromFloat(time))); return d; }
/** Call a function with the given argument specifiers */ JsVar *jsnCallFunction(void *function, JsnArgumentType argumentSpecifier, JsVar *thisParam, JsVar **paramData, int paramCount) { 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]; #ifndef ARM // cdecl on x86 puts FP args elsewhere! 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; // 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 ARM if (JSWAT_IS_64BIT(argType)) argCount = (argCount+1)&~1; #endif if (argCount > MAX_ARGS - (JSWAT_IS_64BIT(argType)?2:1)) { 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 = jsvNewWithFlags(JSV_ARRAY); 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 ARM uint64_t i = *(uint64_t*)&f; #if __WORDSIZE == 64 argData[argCount++] = (size_t)i; #else argData[argCount++] = (size_t)((i) & 0xFFFFFFFF); argData[argCount++] = (size_t)((i>>32) & 0xFFFFFFFF); #endif #else // jsiConsolePrintf("doubleData, %d, %d\n", doubleCount, (int)f); doubleData[doubleCount++] = f; #endif break; } default: assert(0); break; } // on to next! argumentSpecifier >>= JSWAT_BITS; } uint64_t result; // When args<=4 on ARM, everything is passed in registers (so we try and do this case first) if (argCount<=4) { #ifndef ARM assert(doubleCount<=4); if (doubleCount) { if (returnType==JSWAT_JSVARFLOAT) { // On x86, doubles are returned in a floating point unit register JsVarFloat f = ((JsVarFloat (*)(size_t,size_t,size_t,size_t,JsVarFloat,JsVarFloat,JsVarFloat,JsVarFloat))function)(argData[0],argData[1],argData[2],argData[3],doubleData[0],doubleData[1],doubleData[2],doubleData[3]); result = *(uint64_t*)&f; } else { // HERE // jsiConsolePrintf("callFunction: %d, %d, %d\n", JSWAT_IS_64BIT(returnType), function == jswrap_interface_setInterval, (int)doubleData[0]); // if (function == jswrap_interface_setInterval) { // result = (uint32_t)jswrap_interface_setInterval((JsVar *)argData[0], doubleData[0]); // } // else if (JSWAT_IS_64BIT(returnType)) result = ((uint64_t (*)(size_t,size_t,size_t,size_t,JsVarFloat,JsVarFloat,JsVarFloat,JsVarFloat))function)(argData[0],argData[1],argData[2],argData[3],doubleData[0],doubleData[1],doubleData[2],doubleData[3]); else // HERE if (argCount<=2) // ESP8266 fix result = ((uint32_t (*)(size_t,size_t,JsVarFloat,JsVarFloat))function)(argData[0],argData[1],doubleData[0],doubleData[1]); else result = ((uint32_t (*)(size_t,size_t,size_t,size_t,JsVarFloat,JsVarFloat,JsVarFloat,JsVarFloat))function)(argData[0],argData[1],argData[2],argData[3],doubleData[0],doubleData[1],doubleData[2],doubleData[3]); } } else if (returnType==JSWAT_JSVARFLOAT) { // On x86, doubles are returned in a floating point unit register JsVarFloat f = ((JsVarFloat (*)(size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3]); result = *(uint64_t*)&f; } else #endif { if (JSWAT_IS_64BIT(returnType)) result = ((uint64_t (*)(size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3]); else result = ((uint32_t (*)(size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3]); } } else { // else it gets tricky... #ifndef ARM assert(doubleCount==0); if (returnType==JSWAT_JSVARFLOAT) { // On x86, doubles are returned in a floating point unit register JsVarFloat f = ((JsVarFloat (*)(size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3],argData[4],argData[5],argData[6],argData[7],argData[8],argData[9],argData[10],argData[11]); result = *(uint64_t*)&f; } else #endif { if (JSWAT_IS_64BIT(returnType)) result = ((uint64_t (*)(size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3],argData[4],argData[5],argData[6],argData[7],argData[8],argData[9],argData[10],argData[11]); else result = ((uint32_t (*)(size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3],argData[4],argData[5],argData[6],argData[7],argData[8],argData[9],argData[10],argData[11]); } } jsvUnLock(argsArray); switch (returnType) { case JSWAT_VOID: return 0; case JSWAT_JSVAR: // standard variable case JSWAT_ARGUMENT_ARRAY: // a JsVar array containing all subsequent arguments return (JsVar*)(size_t)result; case JSWAT_BOOL: // boolean return jsvNewFromBool(result!=0); case JSWAT_PIN: return jsvNewFromPin((Pin)result); case JSWAT_INT32: // 32 bit int return jsvNewFromInteger((JsVarInt)result); case JSWAT_JSVARFLOAT: // 64 bit float return jsvNewFromFloat(*(JsVarFloat*)&result); default: assert(0); return 0; } }
/** Call a function with the given argument specifiers */ JsVar *jsnCallFunction(void *function, JsnArgumentType argumentSpecifier, JsVar *thisParam, JsVar **paramData, int paramCount) { /*if(paramCount == 3) { jsiConsolePrintf("param[1] = %d\n",jsvGetInteger(paramData[1])); jsiConsolePrintf("param[2] = %d\n",jsvGetInteger(paramData[2])); jsiConsolePrintf("argType = %d\n",argumentSpecifier); }*/ 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]; #ifndef ARM // cdecl on x86 puts FP args elsewhere! int doubleCount = 0; JsVarFloat doubleData[MAX_ARGS]; #endif // prepend the 'this' link if we need one if (argumentSpecifier&JSWAT_THIS_ARG){ //jsiConsolePrintf("this var\n"); argData[argCount++] = (size_t)thisParam; } argumentSpecifier = (argumentSpecifier & JSWAT_ARGUMENTS_MASK) >> JSWAT_BITS; //jsiConsolePrintf("out while : %d\n",argCount); // 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 ARM if (JSWAT_IS_64BIT(argType)){ //jsiConsolePrintf("64 bit\n"); argCount = (argCount+1)&~1; } #endif if (argCount > MAX_ARGS - (JSWAT_IS_64BIT(argType)?2:1)) { jsError("INTERNAL: too many arguments for jsnCallFunction"); } //jsiConsolePrintf("in while : %d\n",argCount); switch (argType) { case JSWAT_JSVAR: { // standard variable argData[argCount++] = (size_t)param; //jsiConsolePrintf("111 : %d\n",argCount - 1); break; } case JSWAT_ARGUMENT_ARRAY: { // a JsVar array containing all subsequent arguments argsArray = jsvNewWithFlags(JSV_ARRAY); 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; //jsiConsolePrintf("222 : %d\n",argCount - 1); break; } case JSWAT_BOOL:{ // boolean argData[argCount++] = jsvGetBool(param); //jsiConsolePrintf("666 : %d\n",argCount - 1); break; } case JSWAT_INT32:{ // 32 bit int argData[argCount++] = (uint32_t)jsvGetInteger(param); //jsiConsolePrintf("333 : %d\n",argCount - 1); break; } case JSWAT_PIN:{ // 16 bit int argData[argCount++] = (uint32_t)jshGetPinFromVar(param); //jsiConsolePrintf("444 : %d\n",argCount - 1); break; } case JSWAT_JSVARFLOAT: { // 64 bit float //jsiConsolePrintf("555\n"); JsVarFloat f = jsvGetFloat(param); //jsiConsolePrintf("params[%d] = %f\n",argCount - 1,f); #ifdef ARM uint64_t i = *(uint64_t*)&f; //jsiConsolePrintf("define ARM\n"); #if __WORDSIZE == 64 argData[argCount++] = (size_t)i; //jsiConsolePrintf("1 - params[%d] = %f\n",argCount - 1,argData[argCount - 1]); #else argData[argCount++] = (size_t)((i) & 0xFFFFFFFF); //jsiConsolePrintf("2 - params[%d] = %d\n",argCount - 1,argData[argCount - 1]); argData[argCount++] = (size_t)((i>>32) & 0xFFFFFFFF); //jsiConsolePrintf("3 - params[%d] = %d\n",argCount - 1,argData[argCount - 1]); #endif #else doubleData[doubleCount++] = f; #endif break; } default: assert(0); break; } // on to next! argumentSpecifier >>= JSWAT_BITS; } //end for while (argumentSpecifier & JSWAT_MASK) //jsiConsolePrintf("native Count = %d\n",argCount - 1); /*for(int i = 0 ; i < argCount; i ++ ){ jsiConsolePrintf("argData[%d] = %d\n",i,argData[i]); }*/ uint64_t result; //jsiConsolePrintf(); // When args<=4 on ARM, everything is passed in registers (so we try and do this case first) if (argCount<=4) { #ifndef ARM assert(doubleCount<=4); if (doubleCount) { if (returnType==JSWAT_JSVARFLOAT) { // On x86, doubles are returned in a floating point unit register //jsiConsolePrintf("111\n"); JsVarFloat f = ((JsVarFloat (*)(size_t,size_t,size_t,size_t,JsVarFloat,JsVarFloat,JsVarFloat,JsVarFloat))function)(argData[0],argData[1],argData[2],argData[3],doubleData[0],doubleData[1],doubleData[2],doubleData[3]); result = *(uint64_t*)&f; } else { //jsiConsolePrintf("222\n"); if (JSWAT_IS_64BIT(returnType)){ result = ((uint64_t (*)(size_t,size_t,size_t,size_t,JsVarFloat,JsVarFloat,JsVarFloat,JsVarFloat))function)(argData[0],argData[1],argData[2],argData[3],doubleData[0],doubleData[1],doubleData[2],doubleData[3]); //jsiConsolePrintf("333\n"); } else result = ((uint32_t (*)(size_t,size_t,size_t,size_t,JsVarFloat,JsVarFloat,JsVarFloat,JsVarFloat))function)(argData[0],argData[1],argData[2],argData[3],doubleData[0],doubleData[1],doubleData[2],doubleData[3]); } } else if (returnType==JSWAT_JSVARFLOAT) { // On x86, doubles are returned in a floating point unit register JsVarFloat f = ((JsVarFloat (*)(size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3]); result = *(uint64_t*)&f; } else #endif { if (JSWAT_IS_64BIT(returnType)) result = ((uint64_t (*)(size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3]); else{ //jsiConsolePrintf("real exec!!!\n"); result = ((uint32_t (*)(size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3]); } } } else { // else it gets tricky... #ifndef ARM assert(doubleCount==0); if (returnType==JSWAT_JSVARFLOAT) { // On x86, doubles are returned in a floating point unit register JsVarFloat f = ((JsVarFloat (*)(size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3],argData[4],argData[5],argData[6],argData[7],argData[8],argData[9],argData[10],argData[11]); result = *(uint64_t*)&f; } else #endif { if (JSWAT_IS_64BIT(returnType)) result = ((uint64_t (*)(size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3],argData[4],argData[5],argData[6],argData[7],argData[8],argData[9],argData[10],argData[11]); else result = ((uint32_t (*)(size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t,size_t))function)(argData[0],argData[1],argData[2],argData[3],argData[4],argData[5],argData[6],argData[7],argData[8],argData[9],argData[10],argData[11]); } } jsvUnLock(argsArray); //jsiConsolePrint("okok\n"); switch (returnType) { case JSWAT_VOID: return 0; case JSWAT_JSVAR: // standard variable case JSWAT_ARGUMENT_ARRAY: // a JsVar array containing all subsequent arguments return (JsVar*)(size_t)result; case JSWAT_BOOL: // boolean return jsvNewFromBool(result!=0); case JSWAT_PIN: return jsvNewFromPin((Pin)result); case JSWAT_INT32: // 32 bit int return jsvNewFromInteger((JsVarInt)result); case JSWAT_JSVARFLOAT: // 64 bit float return jsvNewFromFloat(*(JsVarFloat*)&result); default: assert(0); return 0; } }
/*JSON{ "type" : "staticmethod", "ifndef" : "SAVE_ON_FLASH", "class" : "E", "name" : "FFT", "generate" : "jswrap_espruino_FFT", "params" : [ ["arrReal","JsVar","An array of real values"], ["arrImage","JsVar","An array of imaginary values (or if undefined, all values will be taken to be 0)"], ["inverse","bool","Set this to true if you want an inverse FFT - otherwise leave as 0"] ] } Performs a Fast Fourier Transform (fft) on the supplied data and writes it back into the original arrays. Note that if only one array is supplied, the data written back is the modulus of the complex result `sqrt(r*r+i*i)`. */ void jswrap_espruino_FFT(JsVar *arrReal, JsVar *arrImag, bool inverse) { if (!(jsvIsIterable(arrReal)) || !(jsvIsUndefined(arrImag) || jsvIsIterable(arrImag))) { jsExceptionHere(JSET_ERROR, "Expecting first 2 arguments to be iterable or undefined, not %t and %t", arrReal, arrImag); return; } // get length and work out power of 2 size_t l = (size_t)jsvGetLength(arrReal); size_t pow2 = 1; int order = 0; while (pow2 < l) { pow2 <<= 1; order++; } if (jsuGetFreeStack() < 100+sizeof(double)*pow2*2) { jsExceptionHere(JSET_ERROR, "Insufficient stack for computing FFT"); return; } double *vReal = (double*)alloca(sizeof(double)*pow2); double *vImag = (double*)alloca(sizeof(double)*pow2); unsigned int i; for (i=0;i<pow2;i++) { vReal[i]=0; vImag[i]=0; } // load data JsvIterator it; jsvIteratorNew(&it, arrReal); i=0; while (jsvIteratorHasElement(&it)) { vReal[i++] = jsvIteratorGetFloatValue(&it); jsvIteratorNext(&it); } jsvIteratorFree(&it); if (jsvIsIterable(arrImag)) { jsvIteratorNew(&it, arrImag); i=0; while (i<pow2 && jsvIteratorHasElement(&it)) { vImag[i++] = jsvIteratorGetFloatValue(&it); jsvIteratorNext(&it); } jsvIteratorFree(&it); } // do FFT FFT(inverse ? -1 : 1, order, vReal, vImag); // Put the results back bool useModulus = jsvIsIterable(arrImag); jsvIteratorNew(&it, arrReal); i=0; while (jsvIteratorHasElement(&it)) { JsVarFloat f; if (useModulus) f = jswrap_math_sqrt(vReal[i]*vReal[i] + vImag[i]*vImag[i]); else f = vReal[i]; jsvUnLock(jsvIteratorSetValue(&it, jsvNewFromFloat(f))); i++; jsvIteratorNext(&it); } jsvIteratorFree(&it); if (jsvIsIterable(arrImag)) { jsvIteratorNew(&it, arrImag); i=0; while (jsvIteratorHasElement(&it)) { jsvUnLock(jsvIteratorSetValue(&it, jsvNewFromFloat(vImag[i++]))); jsvIteratorNext(&it); } jsvIteratorFree(&it); } }