/*JSON{ "type" : "function", "name" : "setBusyIndicator", "generate" : "jswrap_interface_setBusyIndicator", "params" : [ ["pin","JsVar",""] ] } When Espruino is busy, set the pin specified here high. Set this to undefined to disable the feature. */ void jswrap_interface_setBusyIndicator(JsVar *pinVar) { Pin oldPin = pinBusyIndicator; pinBusyIndicator = jshGetPinFromVar(pinVar); // we should be busy right now anyway, so set stuff up right if (pinBusyIndicator!=oldPin) { if (oldPin!=NC) jshPinOutput(oldPin, 0); if (pinBusyIndicator!=NC) jshPinOutput(pinBusyIndicator, 1); } }
/*JSON{ "type":"function", "name" : "digitalWrite", "description" : ["Set the digital value of the given pin", "If pin is an array of pins, eg. ```[A2,A1,A0]``` the value will be treated as an integer where the first array element is the MSB" ], "generate" : "jswrap_io_digitalWrite", "params" : [ [ "pin", "JsVar", "The pin to use"], [ "value", "int", "Whether to pulse high (true) or low (false)"] ] }*/ void jswrap_io_digitalWrite(JsVar *pinVar, JsVarInt value) { if (jsvIsArray(pinVar)) { JsVarRef pinName = pinVar->lastChild; // NOTE: start at end and work back! while (pinName) { JsVar *pinNamePtr = jsvLock(pinName); JsVar *pinPtr = jsvSkipName(pinNamePtr); jshPinOutput(jshGetPinFromVar(pinPtr), value&1); jsvUnLock(pinPtr); pinName = pinNamePtr->prevSibling; jsvUnLock(pinNamePtr); value = value>>1; // next bit down } } else {
/** * \brief */ 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 = jsvNewWithFlags(JSV_OBJECT); 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)); // ADC if (inf->analog) { JsVar *an = jsvNewWithFlags(JSV_OBJECT); if (an) { JsVar *arr = jsvNewWithFlags(JSV_ARRAY); 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 = jsvNewWithFlags(JSV_OBJECT); if (funcs) { int i; for (i=0;i<JSH_PININFO_FUNCTIONS;i++) { if (inf->functions[i]) { JsVar *func = jsvNewWithFlags(JSV_OBJECT); 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; }
/*JSON{ "type" : "function", "name" : "digitalWrite", "generate" : "jswrap_io_digitalWrite", "params" : [ ["pin", "JsVar","The pin to use"], ["value", "int","Whether to pulse high (true) or low (false)"] ] } Set the digital value of the given pin. **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"output"` If pin argument is an array of pins (eg. `[A2,A1,A0]`) the value argument will be treated as an array of bits where the last array element is the least significant bit. In this case, pin values are set least significant bit first (from the right-hand side of the array of pins). This means you can use the same pin multiple times, for example `digitalWrite([A1,A1,A0,A0],0b0101)` would pulse A0 followed by A1. If the pin argument is an object with a `write` method, the `write` method will be called with the value passed through. */ void jswrap_io_digitalWrite( JsVar *pinVar, //!< A pin or pins. JsVarInt value //!< The value of the output. ) { // Handle the case where it is an array of pins. if (jsvIsArray(pinVar)) { JsVarRef pinName = jsvGetLastChild(pinVar); // NOTE: start at end and work back! while (pinName) { JsVar *pinNamePtr = jsvLock(pinName); JsVar *pinPtr = jsvSkipName(pinNamePtr); jshPinOutput(jshGetPinFromVar(pinPtr), value&1); jsvUnLock(pinPtr); pinName = jsvGetPrevSibling(pinNamePtr); jsvUnLock(pinNamePtr); value = value>>1; // next bit down } } else if (jsvIsObject(pinVar)) {
/*JSON{ "type" : "method", "class" : "SPI", "name" : "write", "generate" : "jswrap_spi_write", "params" : [ ["data","JsVarArray",["One or more items to write. May be ints, strings, arrays, or objects of the form `{data: ..., count:#}`.","If the last argument is a pin, it is taken to be the NSS pin"]] ] } Write a character or array of characters to SPI - without reading the result back. For maximum speeds, please pass either Strings or Typed Arrays as arguments. */ void jswrap_spi_write( JsVar *parent, //!< JsVar *args //!< ) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); spi_sender spiSend; spi_sender_data spiSendData; if (!jsspiGetSendFunction(parent, &spiSend, &spiSendData)) return; Pin nss_pin = PIN_UNDEFINED; // If the last value is a pin, use it as the NSS pin JsVarInt len = jsvGetArrayLength(args); if (len > 0) { JsVar *last = jsvGetArrayItem(args, len-1); // look at the last value if (jsvIsPin(last)) { nss_pin = jshGetPinFromVar(last); jsvUnLock(jsvArrayPop(args)); } jsvUnLock(last); } // we're only sending (no receive) if (DEVICE_IS_SPI(device)) jshSPISetReceive(device, false); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // Write data jsvIterateCallback(args, (void (*)(int, void *))spiSend, &spiSendData); // Wait until SPI send is finished, and flush data if (DEVICE_IS_SPI(device)) jshSPIWait(device); // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); }
/*JSON{ "type" : "method", "class" : "Pin", "name" : "getMode", "generate" : "jswrap_pin_getMode", "return" : ["JsVar", "The pin mode, as a string"] } Return the current mode of the given pin. See `pinMode` for more information. */ JsVar *jswrap_pin_getMode(JsVar *parent) { return jswrap_io_getPinMode(jshGetPinFromVar(parent)); }
[ "value", "int", "Whether to pulse high (true) or low (false)"] ] }*/ void jswrap_io_digitalWrite(JsVar *pinVar, JsVarInt value) { if (jsvIsArray(pinVar)) { JsVarRef pinName = pinVar->lastChild; // NOTE: start at end and work back! while (pinName) { JsVar *pinNamePtr = jsvLock(pinName); JsVar *pinPtr = jsvSkipName(pinNamePtr); jshPinOutput(jshGetPinFromVar(pinPtr), value&1); jsvUnLock(pinPtr); pinName = pinNamePtr->prevSibling; jsvUnLock(pinNamePtr); value = value>>1; // next bit down } } else { Pin pin = jshGetPinFromVar(pinVar); jshPinOutput(pin, value!=0); } } /*JSON{ "type":"function", "name" : "digitalRead", "description" : ["Get the digital value of the given pin", "If pin is an array of pins, eg. ```[A2,A1,A0]``` the value will be treated as an integer where the first array element is the MSB" ], "generate" : "jswrap_io_digitalRead", "params" : [ [ "pin", "JsVar", "The pin to use"] ], "return" : ["int", "The digital Value of the Pin"] }*/ JsVarInt jswrap_io_digitalRead(JsVar *pinVar) { if (jsvIsArray(pinVar)) { int pins = 0;
/*JSON{ "type":"method", "class": "Pin", "name" : "writeAtTime", "ifndef" : "SAVE_ON_FLASH", "description" : "Sets the output state of the pin to the parameter given at the specified time", "generate" : "jswrap_pin_writeAtTime", "params" : [ [ "value", "bool", "Whether to set output high (true/1) or low (false/0)"], ["time", "float", "Time at which to write"] ] }*/ void jswrap_pin_writeAtTime(JsVar *parent, bool value, JsVarFloat time) { Pin pin = jshGetPinFromVar(parent); JsSysTime sTime = jshGetTimeFromMilliseconds(time*1000); jstPinOutputAtTime(sTime, &pin, 1, value); }
/*JSON{ "type":"method", "class": "Pin", "name" : "write", "description" : "Sets the output state of the pin to the parameter given", "generate" : "jswrap_pin_write", "params" : [ [ "value", "bool", "Whether to set output high (true/1) or low (false/0)"] ] }*/ void jswrap_pin_write(JsVar *parent, bool value) { Pin pin = jshGetPinFromVar(parent); jshPinOutput(pin, value); }
/*JSON{ "type":"method", "class": "Pin", "name" : "reset", "description" : "Sets the output state of the pin to a 0", "generate" : "jswrap_pin_reset" }*/ void jswrap_pin_reset(JsVar *parent) { Pin pin = jshGetPinFromVar(parent); jshPinOutput(pin, 0); }
/*JSON{ "type":"method", "class": "Pin", "name" : "read", "description" : "Returns the input state of the pin as a boolean", "generate" : "jswrap_pin_read", "return" : ["bool", "Whether pin is a logical 1 or 0"] }*/ bool jswrap_pin_read(JsVar *parent) { Pin pin = jshGetPinFromVar(parent); return jshPinInput(pin); }
/*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; return jsvNewFromPin(pin); }
/*JSON{ "type" : "method", "class" : "Pin", "name" : "mode", "generate" : "jswrap_pin_mode", "params" : [ ["mode", "JsVar", "The mode - a string that is either 'analog', 'input', 'input_pullup', 'input_pulldown', 'output', 'opendrain', 'af_output' or 'af_opendrain'. Do not include this argument if you want to revert to automatic pin mode setting."] ] } Set the mode of the given pin. See [`pinMode`](#l__global_pinMode) for more information on pin modes. */ void jswrap_pin_mode(JsVar *parent, JsVar *mode) { jswrap_io_pinMode(jshGetPinFromVar(parent), mode); }
/** Write the pin name to a string. String must have at least 8 characters (to be safe) */ void jshGetPinString(char *result, Pin pin) { result[0] = 0; // just in case #ifdef PIN_NAMES_DIRECT if (jshIsPinValid(pin)) { result[0]='A'+pinInfo[pin].port-JSH_PORTA; itostr(pinInfo[pin].pin-JSH_PIN0,&result[1],10); #else if ( #if JSH_PORTA_OFFSET!=0 pin>=JSH_PORTA_OFFSET && #endif pin<JSH_PORTA_OFFSET+JSH_PORTA_COUNT) { result[0]='A'; itostr(pin-JSH_PORTA_OFFSET,&result[1],10); } else if (pin>=JSH_PORTB_OFFSET && pin<JSH_PORTB_OFFSET+JSH_PORTB_COUNT) { result[0]='B'; itostr(pin-JSH_PORTB_OFFSET,&result[1],10); } else if (pin>=JSH_PORTC_OFFSET && pin<JSH_PORTC_OFFSET+JSH_PORTC_COUNT) { result[0]='C'; itostr(pin-JSH_PORTC_OFFSET,&result[1],10); } else if (pin>=JSH_PORTD_OFFSET && pin<JSH_PORTD_OFFSET+JSH_PORTD_COUNT) { result[0]='D'; itostr(pin-JSH_PORTD_OFFSET,&result[1],10); #if JSH_PORTE_OFFSET!=-1 } else if (pin>=JSH_PORTE_OFFSET && pin<JSH_PORTE_OFFSET+JSH_PORTE_COUNT) { result[0]='E'; itostr(pin-JSH_PORTE_OFFSET,&result[1],10); #endif #if JSH_PORTF_OFFSET!=-1 } else if (pin>=JSH_PORTF_OFFSET && pin<JSH_PORTF_OFFSET+JSH_PORTF_COUNT) { result[0]='F'; itostr(pin-JSH_PORTF_OFFSET,&result[1],10); #endif #if JSH_PORTG_OFFSET!=-1 } else if (pin>=JSH_PORTG_OFFSET && pin<JSH_PORTG_OFFSET+JSH_PORTG_COUNT) { result[0]='G'; itostr(pin-JSH_PORTG_OFFSET,&result[1],10); #endif #if JSH_PORTH_OFFSET!=-1 } else if (pin>=JSH_PORTH_OFFSET && pin<JSH_PORTH_OFFSET+JSH_PORTH_COUNT) { result[0]='H'; itostr(pin-JSH_PORTH_OFFSET,&result[1],10); #endif #endif } else { strncpy(result, "UNKNOWN", 8); } } /// Given a var, convert it to a pin ID (or -1 if it doesn't exist). safe for undefined! Pin jshGetPinFromVar(JsVar *pinv) { if (jsvIsString(pinv) && pinv->varData.str[5]==0/*should never be more than 4 chars!*/) { return jshGetPinFromString(&pinv->varData.str[0]); } else if (jsvIsInt(pinv) /* This also tests for the Pin datatype */) { return (Pin)jsvGetInteger(pinv); } else return PIN_UNDEFINED; } Pin jshGetPinFromVarAndUnLock(JsVar *pinv) { Pin pin = jshGetPinFromVar(pinv); jsvUnLock(pinv); return pin; }
/*JSON{ "type":"function", "name" : "setSleepIndicator", "description" : "When Espruino is asleep, set the pin specified here high. Set this to undefined to disable the feature.", "generate" : "jswrap_interface_setSleepIndicator", "params" : [ [ "pin", "JsVar", ""] ] }*/ void jswrap_interface_setSleepIndicator(JsVar *pinVar) { pinSleepIndicator = jshGetPinFromVar(pinVar); }
/** 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; }