/*JSON{ "type" : "method", "class" : "I2C", "name" : "readFrom", "generate" : "jswrap_i2c_readFrom", "params" : [ ["address","JsVar","The 7 bit address of the device to request bytes from, or an object of the form `{address:12, stop:false}` to send this data without a STOP signal."], ["quantity","int32","The number of bytes to request"] ], "return" : ["JsVar","The data that was returned - as a Uint8Array"], "return_object" : "Uint8Array" } Request bytes from the given slave device, and return them as a Uint8Array (packed array of bytes). This is like using Arduino Wire's requestFrom, available and read functions. Sends a STOP */ JsVar *jswrap_i2c_readFrom(JsVar *parent, JsVar *addressVar, int nBytes) { IOEventFlags device = jsiGetDeviceFromClass(parent); if (!DEVICE_IS_I2C(device)) return 0; bool sendStop = true; int address = i2c_get_address(addressVar, &sendStop); if (nBytes<=0) return 0; if ((unsigned int)nBytes+256 > jsuGetFreeStack()) { jsExceptionHere(JSET_ERROR, "Not enough free stack to receive this amount of data"); return 0; } unsigned char *buf = (unsigned char *)alloca((size_t)nBytes); jshI2CRead(device, (unsigned char)address, nBytes, buf, sendStop); JsVar *array = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, nBytes); if (array) { JsvArrayBufferIterator it; jsvArrayBufferIteratorNew(&it, array, 0); unsigned int i; for (i=0;i<(unsigned)nBytes;i++) { jsvArrayBufferIteratorSetByteValue(&it, (char)buf[i]); jsvArrayBufferIteratorNext(&it); } jsvArrayBufferIteratorFree(&it); } return array; }
/*JSON{ "type" : "method", "class" : "ArrayBufferView", "name" : "map", "generate" : "jswrap_arraybufferview_map", "params" : [ ["function","JsVar","Function used to map one item to another"], ["thisArg","JsVar","if specified, the function is called with 'this' set to thisArg (optional)"] ], "return" : ["JsVar","An array containing the results"], "return_object" : "ArrayBufferView" } Return an array which is made from the following: ```A.map(function) = [function(A[0]), function(A[1]), ...]``` **Note:** This returns an `ArrayBuffer` of the same type it was called on. To get an `Array`, use `Array.map`, eg. `[].map.call(myArray, x=>x+1)` */ JsVar *jswrap_arraybufferview_map(JsVar *parent, JsVar *funcVar, JsVar *thisVar) { if (!jsvIsArrayBuffer(parent)) { jsExceptionHere(JSET_ERROR, "ArrayBufferView.map can only be called on an ArrayBufferView"); return 0; } if (!jsvIsFunction(funcVar)) { jsExceptionHere(JSET_ERROR, "ArrayBufferView.map's first argument should be a function"); return 0; } if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) { jsExceptionHere(JSET_ERROR, "ArrayBufferView.map's second argument should be undefined, or an object"); return 0; } // create ArrayBuffer result JsVarDataArrayBufferViewType arrayBufferType = parent->varData.arraybuffer.type; JsVar *array = jsvNewTypedArray(arrayBufferType, (JsVarInt)jsvGetArrayBufferLength(parent)); if (!array) return 0; // now iterate JsvIterator it; // TODO: if we really are limited to ArrayBuffers, this could be an ArrayBufferIterator. jsvIteratorNew(&it, parent, JSIF_EVERY_ARRAY_ELEMENT); JsvArrayBufferIterator itdst; jsvArrayBufferIteratorNew(&itdst, array, 0); while (jsvIteratorHasElement(&it)) { JsVar *index = jsvIteratorGetKey(&it); if (jsvIsInt(index)) { JsVarInt idxValue = jsvGetInteger(index); JsVar *args[3], *mapped; args[0] = jsvIteratorGetValue(&it); args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index args[2] = parent; mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args); jsvUnLockMany(2,args); if (mapped) { jsvArrayBufferIteratorSetValue(&itdst, mapped); jsvUnLock(mapped); } } jsvUnLock(index); jsvIteratorNext(&it); jsvArrayBufferIteratorNext(&itdst); } jsvIteratorFree(&it); jsvArrayBufferIteratorFree(&itdst); return array; }
/*JSON{ "type" : "constructor", "class" : "Waveform", "name" : "Waveform", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_waveform_constructor", "params" : [ ["samples","int32","The number of samples"], ["options","JsVar","Optional options struct `{doubleBuffer:bool, bits : 8/16}` where: `doubleBuffer` is whether to allocate two buffers or not (default false), and bits is the amount of bits to use (default 8)."] ], "return" : ["JsVar","An Waveform object"] } Create a waveform class. This allows high speed input and output of waveforms. It has an internal variable called `buffer` (as well as `buffer2` when double-buffered - see `options` below) which contains the data to input/output. When double-buffered, a 'buffer' event will be emitted each time a buffer is finished with (the argument is that buffer). When the recording stops, a 'finish' event will be emitted (with the first argument as the buffer). */ JsVar *jswrap_waveform_constructor(int samples, JsVar *options) { if (samples<=0) { jsExceptionHere(JSET_ERROR, "Samples must be greater than 0"); return 0; } bool doubleBuffer = false; bool use16bit = false; if (jsvIsObject(options)) { doubleBuffer = jsvGetBoolAndUnLock(jsvObjectGetChild(options, "doubleBuffer", 0)); int bits = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "bits", 0)); if (bits!=0 && bits!=8 && bits!=16) { jsExceptionHere(JSET_ERROR, "Invalid number of bits"); return 0; } else if (bits==16) use16bit = true; } else if (!jsvIsUndefined(options)) { jsExceptionHere(JSET_ERROR, "Expecting options to be undefined or an Object, not %t", options); } JsVarDataArrayBufferViewType bufferType = use16bit ? ARRAYBUFFERVIEW_UINT16 : ARRAYBUFFERVIEW_UINT8; JsVar *arrayBuffer = jsvNewTypedArray(bufferType, samples); JsVar *arrayBuffer2 = 0; if (doubleBuffer) arrayBuffer2 = jsvNewTypedArray(bufferType, samples); JsVar *waveform = jspNewObject(0, "Waveform"); if (!waveform || !arrayBuffer || (doubleBuffer && !arrayBuffer2)) { jsvUnLock3(waveform,arrayBuffer,arrayBuffer2); // out of memory return 0; } jsvObjectSetChildAndUnLock(waveform, "buffer", arrayBuffer); if (arrayBuffer2) jsvObjectSetChildAndUnLock(waveform, "buffer2", arrayBuffer2); return waveform; }
/*JSON{ "type" : "method", "class" : "OneWire", "name" : "read", "generate" : "jswrap_onewire_read", "params" : [["count","JsVar","(optional) The amount of bytes to read"]], "return" : ["JsVar","The byte that was read, or a Uint8Array if count was specified and >=0"] } Read a byte */ JsVar *jswrap_onewire_read(JsVar *parent, JsVar *count) { Pin pin = onewire_getpin(parent); if (!jshIsPinValid(pin)) return 0; if (jsvIsNumeric(count)) { JsVarInt c = jsvGetInteger(count); JsVar *arr = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, c); if (!arr) return 0; JsvArrayBufferIterator it; jsvArrayBufferIteratorNew(&it, arr, 0); while (c--) { jsvArrayBufferIteratorSetByteValue(&it, (char)OneWireRead(pin, 8)); jsvArrayBufferIteratorNext(&it); } jsvArrayBufferIteratorFree(&it); return arr; } else { return jsvNewFromInteger(OneWireRead(pin, 8)); } }
JsVar *jswrap_io_peek(JsVarInt addr, JsVarInt count, int wordSize) { if (count<=1) { return jsvNewFromLongInteger((long long)_jswrap_io_peek(addr, wordSize)); } else { JsVarDataArrayBufferViewType aType; if (wordSize==1) aType=ARRAYBUFFERVIEW_UINT8; if (wordSize==2) aType=ARRAYBUFFERVIEW_UINT16; if (wordSize==4) aType=ARRAYBUFFERVIEW_UINT32; JsVar *arr = jsvNewTypedArray(aType, count); if (!arr) return 0; JsvArrayBufferIterator it; jsvArrayBufferIteratorNew(&it, arr, 0); while (jsvArrayBufferIteratorHasElement(&it)) { jsvArrayBufferIteratorSetIntegerValue(&it, (JsVarInt)_jswrap_io_peek(addr, wordSize)); addr += wordSize; jsvArrayBufferIteratorNext(&it); } jsvArrayBufferIteratorFree(&it); return arr; } }
/** * Send data through SPI. * The data can be in a variety of formats including: * * `numeric` - A single byte is transmitted. * * `string` - Each character in the string is transmitted. * * `iterable` - An iterable object is transmitted. * \return the Received bytes (MISO). This is byte array. */ JsVar *jswrap_spi_send( JsVar *parent, //!< A description of the SPI device to send data through. JsVar *srcdata, //!< The data to send through SPI. Pin nss_pin //!< The pin to toggle low then high (CS) ) { // Debug // jsiConsolePrintf("jswrap_spi_send called: parent=%j, srcdata=%j, nss_pin=%p\n", parent, srcdata, nss_pin); NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); jswrap_spi_send_data data; if (!jsspiGetSendFunction(parent, &data.spiSend, &data.spiSendData)) return 0; JsVar *dst = 0; // we're sending and receiving if (DEVICE_IS_SPI(device)) jshSPISetReceive(device, true); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // Now that we are setup, we can send the data. // Handle the data being a single byte value if (jsvIsNumeric(srcdata)) { int r = data.spiSend((unsigned char)jsvGetInteger(srcdata), &data.spiSendData); if (r<0) r = data.spiSend(-1, &data.spiSendData); dst = jsvNewFromInteger(r); // retrieve the byte (no send!) } // Handle the data being a string else if (jsvIsString(srcdata)) { dst = jsvNewFromEmptyString(); JsvStringIterator it; jsvStringIteratorNew(&it, srcdata, 0); int incount = 0, outcount = 0; while (jsvStringIteratorHasChar(&it) && !jspIsInterrupted()) { unsigned char in = (unsigned char)jsvStringIteratorGetChar(&it); incount++; int out = data.spiSend(in, &data.spiSendData); if (out>=0) { outcount++; char outc = (char)out; jsvAppendStringBuf(dst, (char*)&outc, 1); } jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); // finally add the remaining bytes (no send!) while (outcount < incount && !jspIsInterrupted()) { outcount++; unsigned char out = (unsigned char)data.spiSend(-1, &data.spiSendData); jsvAppendStringBuf(dst, (char*)&out, 1); } } // Handle the data being an iterable. else { int nBytes = jsvIterateCallbackCount(srcdata); dst = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, nBytes); if (dst) { data.rxAmt = data.txAmt = 0; jsvArrayBufferIteratorNew(&data.it, dst, 0); // Write data jsvIterateCallback(srcdata, (void (*)(int, void *))jswrap_spi_send_cb, &data); // Wait until SPI send is finished, and flush data while (data.rxAmt < data.txAmt && !jspIsInterrupted()) jswrap_spi_send_cb(-1, &data); jsvArrayBufferIteratorFree(&data.it); } } // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); return dst; }
JsVar *jswrap_spi_send(JsVar *parent, JsVar *srcdata, Pin nss_pin) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); jswrap_spi_send_data data; if (!jsspiGetSendFunction(parent, &data.spiSend, &data.spiSendData)) return 0; JsVar *dst = 0; // we're sending and receiving if (DEVICE_IS_SPI(device)) jshSPISetReceive(device, true); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // send data if (jsvIsNumeric(srcdata)) { int r = data.spiSend((unsigned char)jsvGetInteger(srcdata), &data.spiSendData); if (r<0) r = data.spiSend(-1, &data.spiSendData); dst = jsvNewFromInteger(r); // retrieve the byte (no send!) } else if (jsvIsString(srcdata)) { dst = jsvNewFromEmptyString(); JsvStringIterator it; jsvStringIteratorNew(&it, srcdata, 0); int incount = 0, outcount = 0; while (jsvStringIteratorHasChar(&it) && !jspIsInterrupted()) { unsigned char in = (unsigned char)jsvStringIteratorGetChar(&it); incount++; int out = data.spiSend(in, &data.spiSendData); if (out>=0) { outcount++; char outc = (char)out; jsvAppendStringBuf(dst, (char*)&outc, 1); } jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); // finally add the remaining bytes (no send!) while (outcount < incount && !jspIsInterrupted()) { outcount++; unsigned char out = (unsigned char)data.spiSend(-1, &data.spiSendData); jsvAppendStringBuf(dst, (char*)&out, 1); } } else { int nBytes = jsvIterateCallbackCount(srcdata); dst = jsvNewTypedArray(ARRAYBUFFERVIEW_UINT8, nBytes); if (dst) { data.rxAmt = data.txAmt = 0; jsvArrayBufferIteratorNew(&data.it, dst, 0); // Write data jsvIterateCallback(srcdata, (void (*)(int, void *))jswrap_spi_send_cb, &data); // Wait until SPI send is finished, and flush data while (data.rxAmt < data.txAmt && !jspIsInterrupted()) jswrap_spi_send_cb(-1, &data); jsvArrayBufferIteratorFree(&data.it); } } // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); return dst; }