/*JSON{ "type" : "staticmethod", "class" : "Trig", "name" : "setup", "generate" : "jswrap_trig_setup", "params" : [ ["pin","pin","The pin to use for triggering"], ["options","JsVar","Additional options as an object. defaults are: ```{teethTotal:60,teethMissing:2,minRPM:30,keyPosition:0}```"] ] } Initialise the trigger class */ void jswrap_trig_setup(Pin pin, JsVar *options) { if (!jshIsPinValid(pin)) { jsError("Invalid pin supplied as an argument to Trig.setup"); return; } TriggerStruct *trig = &mainTrigger; // static info trig->teethMissing = 2; trig->teethTotal = 60; trig->keyPosition = 0; JsVarFloat minRPM = 30; if (jsvIsObject(options)) { JsVar *v; v = jsvObjectGetChild(options, "teethMissing", 0); if (!jsvIsUndefined(v)) trig->teethMissing = (unsigned char)jsvGetInteger(v); jsvUnLock(v); v = jsvObjectGetChild(options, "teethTotal", 0); if (!jsvIsUndefined(v)) trig->teethTotal = (unsigned char)jsvGetInteger(v); jsvUnLock(v); v = jsvObjectGetChild(options, "minRPM", 0); if (!jsvIsUndefined(v)) minRPM = jsvGetFloat(v); jsvUnLock(v); v = jsvObjectGetChild(options, "keyPosition", 0); if (!jsvIsUndefined(v)) trig->keyPosition = jsvGetFloat(v); jsvUnLock(v); } trig->maxTooth = (unsigned int)jshGetTimeFromMilliseconds(60000 / (JsVarFloat)(trig->teethTotal * minRPM)); // semi-static info int i; for (i=0;i<TRIGGER_TRIGGERS_COUNT;i++) { trig->triggers[i].tooth = TRIGGERPOINT_TOOTH_DISABLE; trig->triggers[i].newTooth = TRIGGERPOINT_TOOTH_DISABLE; } // dynamic info trig->lastTime = jshGetSystemTime(); trig->avrTrigger = (unsigned int)jshGetTimeFromMilliseconds(10); // average time for a trigger pulse trig->avrTooth = (unsigned int)jshGetTimeFromMilliseconds(10); // average time for a tooth trig->currTooth = 0; trig->teethSinceStart = 0; trig->wrongTriggerTeeth = 0; // finally set up the watch! if (jshIsPinValid(trig->sensorPin)) jshPinWatch(trig->sensorPin, false); trig->sensorPin = pin; jshPinWatch(trig->sensorPin, true); }
/*JSON{ "type" : "method", "class" : "Number", "name" : "toFixed", "generate" : "jswrap_number_toFixed", "params" : [ ["decimalPlaces","int32","A number between 0 and 20 specifying the number of decimal digits after the decimal point"] ], "return" : ["JsVar","A string"] } Format the number as a fixed point number */ JsVar *jswrap_number_toFixed(JsVar *parent, int decimals) { if (decimals<0) decimals=0; if (decimals>20) decimals=20; char buf[JS_NUMBER_BUFFER_SIZE]; ftoa_bounded_extra(jsvGetFloat(parent), buf, sizeof(buf), 10, decimals); return jsvNewFromString(buf); }
/*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); }
void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value) { if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return; assert(!it->hasAccessedElement); // we just haven't implemented this case yet char data[8]; int i,dataLen = (int)JSV_ARRAYBUFFER_GET_SIZE(it->type); if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { jsvArrayBufferIteratorFloatToData(data, (unsigned)dataLen, it->type, jsvGetFloat(value)); } else { jsvArrayBufferIteratorIntToData(data, (unsigned)dataLen, it->type, jsvGetInteger(value)); } if (it->type & ARRAYBUFFERVIEW_BIG_ENDIAN) { for (i=dataLen-1;i>=0;i--) { jsvStringIteratorSetChar(&it->it, data[i]); if (dataLen!=1) jsvStringIteratorNext(&it->it); } } else { for (i=0;i<dataLen;i++) { jsvStringIteratorSetChar(&it->it, data[i]); if (dataLen!=1) jsvStringIteratorNext(&it->it); } } if (dataLen!=1) it->hasAccessedElement = true; }
void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value) { if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return; assert(!it->hasAccessedElement); // we just haven't implemented this case yet char data[8]; unsigned int i,dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type); if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) { JsVarFloat v = jsvGetFloat(value); ; if (dataLen==4) { float f = (float)v; memcpy(data,&f,dataLen); } else if (dataLen==8) { double f = (double)v; memcpy(data,&f,dataLen); } else assert(0); } else { JsVarInt v = jsvGetInteger(value); // we don't care about sign when writing - as it gets truncated if (dataLen==1) { char c = (char)v; memcpy(data,&c,dataLen); } else if (dataLen==2) { short c = (short)v; memcpy(data,&c,dataLen); } else if (dataLen==4) { int c = (int)v; memcpy(data,&c,dataLen); } else if (dataLen==8) { long long c = (long long)v; memcpy(data,&c,dataLen); } else assert(0); } for (i=0;i<dataLen;i++) { jsvStringIteratorSetChar(&it->it, data[i]); if (dataLen!=1) jsvStringIteratorNext(&it->it); } if (dataLen!=1) it->hasAccessedElement = true; }
/*JSON{ "type":"function", "name" : "isNaN", "description" : "Whether the x is NaN (Not a Number) or not", "generate" : "jswrap_isNaN", "params" : [ [ "x", "JsVar", ""] ], "return" : ["bool", "True is the value is NaN, false if not."] }*/ bool jswrap_isNaN(JsVar *v) { if (jsvIsUndefined(v) || jsvIsObject(v) || (jsvIsFloat(v) && isnan(jsvGetFloat(v)))) return true; if (jsvIsString(v)) { // this is where is can get a bit crazy bool allWhiteSpace = true; JsvStringIterator it; jsvStringIteratorNew(&it,v,0); while (jsvStringIteratorHasChar(&it)) { if (!isWhitespace(jsvStringIteratorGetChar(&it))) { allWhiteSpace = false; break; } jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); if (allWhiteSpace) return false; return isnan(jsvGetFloat(v)); } return false; }
/*JSON{ "type" : "method", "class" : "Object", "name" : "toString", "generate" : "jswrap_object_toString", "params" : [ ["radix","JsVar","If the object is an integer, the radix (between 2 and 36) to use. NOTE: Setting a radix does not work on floating point numbers."] ], "return" : ["JsVar","A String representing the object"] } Convert the Object to a string */ JsVar *jswrap_object_toString(JsVar *parent, JsVar *arg0) { if (jsvIsInt(arg0) && jsvIsNumeric(parent)) { JsVarInt radix = jsvGetInteger(arg0); if (radix>=2 && radix<=36) { char buf[JS_NUMBER_BUFFER_SIZE]; if (jsvIsInt(parent)) itostr(jsvGetInteger(parent), buf, (unsigned int)radix); else ftoa_bounded_extra(jsvGetFloat(parent), buf, sizeof(buf), (int)radix, -1); return jsvNewFromString(buf); } } return jsvAsString(parent, false); }
/*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); }
/*JSON{ "type" : "function", "name" : "digitalPulse", "generate" : "jswrap_io_digitalPulse", "params" : [ ["pin","pin","The pin to use"], ["value","bool","Whether to pulse high (true) or low (false)"], ["time","JsVar","A time in milliseconds, or an array of times (in which case a square wave will be output starting with a pulse of 'value')"] ] } 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(A0,1,[5,2,4]);` pulses A0 high for 5ms, low for 2ms, and high for 4ms **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"output"` digitalPulse is for SHORT pulses that need to be very accurate. If you're doing anything over a few milliseconds, use setTimeout instead. */ void jswrap_io_digitalPulse(Pin pin, bool value, JsVar *times) { if (jsvIsNumeric(times)) { JsVarFloat time = jsvGetFloat(times); if (time<0 || isnan(time)) { jsExceptionHere(JSET_ERROR, "Pulse Time given for digitalPulse is less than 0, or not a number"); } else { jshPinPulse(pin, value, time); } } else if (jsvIsIterable(times)) { // iterable, so output a square wave JsvIterator it; jsvIteratorNew(&it, times); while (jsvIteratorHasElement(&it)) { JsVarFloat time = jsvIteratorGetFloatValue(&it); if (time>=0 && !isnan(time)) jshPinPulse(pin, value, time); value = !value; jsvIteratorNext(&it); } jsvIteratorFree(&it); } else { jsExceptionHere(JSET_ERROR, "Expecting a number or array, got %t", times); } }
/** 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; } }
/** 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; }