Beispiel #1
0
/*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;
}
Beispiel #2
0
/*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);
}
Beispiel #3
0
/*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);
}
Beispiel #4
0
/*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;
}
Beispiel #5
0
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);
  }
}
Beispiel #7
0
/*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);
}
Beispiel #8
0
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);
  }
}
Beispiel #9
0
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
  }
  }
}
Beispiel #10
0
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
  }
}
Beispiel #11
0
JsVar *jswrap_date_from_milliseconds(JsVarFloat time) {
  JsVar *d = jspNewObject(0,"Date");
  if (!d) return 0;
  jsvUnLock(jsvObjectSetChild(d, "ms", jsvNewFromFloat(time)));
  return d;
}
Beispiel #12
0
/** 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;
  }
}
Beispiel #13
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;
  }
}
Beispiel #14
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);
  }
}