/*JSON{ "type" : "method", "class" : "ArrayBufferView", "name" : "set", "generate" : "jswrap_arraybufferview_set", "params" : [ ["arr","JsVar","Floating point index to access"], ["offset","int32","The offset in this array at which to write the values (optional)"] ] } Copy the contents of `array` into this one, mapping `this[x+offset]=array[x];` */ void jswrap_arraybufferview_set(JsVar *parent, JsVar *arr, int offset) { if (!(jsvIsString(arr) || jsvIsArray(arr) || jsvIsArrayBuffer(arr))) { jsExceptionHere(JSET_ERROR, "Expecting first argument to be an array, not %t", arr); return; } JsvIterator itsrc; jsvIteratorNew(&itsrc, arr); JsvArrayBufferIterator itdst; jsvArrayBufferIteratorNew(&itdst, parent, (size_t)offset); bool useInts = !JSV_ARRAYBUFFER_IS_FLOAT(itdst.type) || jsvIsString(arr); while (jsvIteratorHasElement(&itsrc) && jsvArrayBufferIteratorHasElement(&itdst)) { if (useInts) { jsvArrayBufferIteratorSetIntegerValue(&itdst, jsvIteratorGetIntegerValue(&itsrc)); } else { JsVar *value = jsvIteratorGetValue(&itsrc); jsvArrayBufferIteratorSetValue(&itdst, value); jsvUnLock(value); } jsvArrayBufferIteratorNext(&itdst); jsvIteratorNext(&itsrc); } jsvArrayBufferIteratorFree(&itdst); jsvIteratorFree(&itsrc); }
/*JSON{ "type" : "method", "class" : "SPI", "name" : "send4bit", "generate" : "jswrap_spi_send4bit", "params" : [ ["data","JsVar","The data to send - either an integer, array, or string"], ["bit0","int32","The 4 bits to send for a 0 (MSB first)"], ["bit1","int32","The 4 bits to send for a 1 (MSB first)"], ["nss_pin","pin","An nSS pin - this will be lowered before SPI output and raised afterwards (optional). There will be a small delay between when this is lowered and when sending starts, and also between sending finishing and it being raised."] ] } Send data down SPI, using 4 bits for each 'real' bit (MSB first). This can be useful for faking one-wire style protocols Sending multiple bytes in one call to send is preferable as they can then be transmitted end to end. Using multiple calls to send() will result in significantly slower transmission speeds. */ void jswrap_spi_send4bit(JsVar *parent, JsVar *srcdata, int bit0, int bit1, Pin nss_pin) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); if (!DEVICE_IS_SPI(device)) { jsExceptionHere(JSET_ERROR, "SPI.send4bit only works on hardware SPI"); return; } jshSPISet16(device, true); // 16 bit output if (bit0==0 && bit1==0) { bit0 = 0x01; bit1 = 0x03; } bit0 = bit0 & 0x0F; bit1 = bit1 & 0x0F; if (!jshIsDeviceInitialised(device)) { JshSPIInfo inf; jshSPIInitInfo(&inf); jshSPISetup(device, &inf); } // we're just sending (no receive) jshSPISetReceive(device, false); // assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, false); // send data if (jsvIsNumeric(srcdata)) { jsspiSend4bit(device, (unsigned char)jsvGetInteger(srcdata), bit0, bit1); } else if (jsvIsIterable(srcdata)) { jshInterruptOff(); JsvIterator it; jsvIteratorNew(&it, srcdata); while (jsvIteratorHasElement(&it)) { unsigned char in = (unsigned char)jsvIteratorGetIntegerValue(&it); jsspiSend4bit(device, in, bit0, bit1); jsvIteratorNext(&it); } jsvIteratorFree(&it); jshInterruptOn(); } else { jsExceptionHere(JSET_ERROR, "Variable type %t not suited to transmit operation", srcdata); } jshSPIWait(device); // wait until SPI send finished and clear the RX buffer // de-assert NSS if (nss_pin!=PIN_UNDEFINED) jshPinOutput(nss_pin, true); jshSPISet16(device, false); // back to 8 bit }
void jswrap_io_poke(JsVarInt addr, JsVar *data, int wordSize) { if (jsvIsNumeric(data)) { _jswrap_io_poke(addr, (uint32_t)jsvGetInteger(data), wordSize); } else if (jsvIsIterable(data)) { JsvIterator it; jsvIteratorNew(&it, data); while (jsvIteratorHasElement(&it)) { _jswrap_io_poke(addr, (uint32_t)jsvIteratorGetIntegerValue(&it), wordSize); addr += wordSize; jsvIteratorNext(&it); } jsvIteratorFree(&it); } }
/*JSON{ "type":"method", "class": "Serial", "name" : "write", "description" : "Write a character or array of characters to the serial port - without a line feed", "generate" : "jswrap_serial_write", "params" : [ [ "data", "JsVar", "A byte, a string, or an array of bytes to write"] ] }*/ void jswrap_serial_write(JsVar *parent, JsVar *data) { NOT_USED(parent); IOEventFlags device = jsiGetDeviceFromClass(parent); if (jsvIsNumeric(data)) { jshTransmit(device, (unsigned char)jsvGetInteger(data)); } else if (jsvIsIterable(data)) { JsvIterator it; jsvIteratorNew(&it, data); while (jsvIteratorHasElement(&it)) { jshTransmit(device, (unsigned char)jsvIteratorGetIntegerValue(&it)); jsvIteratorNext(&it); } jsvIteratorFree(&it); } else { jsWarn("Data supplied was not an integer - or iterable"); } }
/*JSON{ "type":"staticmethod", "class" : "E", "name" : "openFile", "generate" : "jswrap_E_openFile", "description" : [ "Open a file" ], "params" : [ [ "path", "JsVar", "the path to the file to open." ], [ "mode", "JsVar", "The mode to use when opening the file. Valid values for mode are 'r' for read, 'w' for write new, 'w+' for write existing, and 'a' for append. If not specified, the default is 'r'."] ], "return" : ["JsVar", "A File object"] }*/ JsVar *jswrap_E_openFile(JsVar* path, JsVar* mode) { FRESULT res = FR_INVALID_NAME; JsFile file; file.fileVar = 0; FileMode fMode = FM_NONE; if (jsfsInit()) { JsVar *arr = fsGetArray(true); if (!arr) return 0; // out of memory char pathStr[JS_DIR_BUF_SIZE] = ""; char modeStr[3] = "r"; if (!jsvIsUndefined(path)) { jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); if (!jsvIsUndefined(mode)) jsvGetString(mode, modeStr, 3); #ifndef LINUX BYTE ff_mode = 0; bool append = false; #endif if(strcmp(modeStr,"r") == 0) { fMode = FM_READ; #ifndef LINUX ff_mode = FA_READ | FA_OPEN_EXISTING; #endif } else if(strcmp(modeStr,"a") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; append = true; #endif } else if(strcmp(modeStr,"w") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_CREATE_ALWAYS; #endif } else if(strcmp(modeStr,"w+") == 0) { fMode = FM_READ_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; #endif } if(fMode != FM_NONE && allocateJsFile(&file, fMode, FT_FILE)) { #ifndef LINUX if ((res=f_open(&file.data.handle, pathStr, ff_mode)) == FR_OK) { if (append) f_lseek(&file.data.handle, file.data.handle.fsize); // move to end of file #else file.data.handle = fopen(pathStr, modeStr); if (file.data.handle) { res=FR_OK; #endif file.data.state = FS_OPEN; fileSetVar(&file); // add to list of open files jsvArrayPush(arr, file.fileVar); jsvUnLock(arr); } else { // File open failed jsvUnLock(file.fileVar); file.fileVar = 0; } if(res != FR_OK) jsfsReportError("Could not open file", res); } } else { jsError("Path is undefined"); } } return file.fileVar; } /*JSON{ "type" : "method", "class" : "File", "name" : "close", "generate_full" : "jswrap_file_close(parent)", "description" : [ "Close an open file."] }*/ void jswrap_file_close(JsVar* parent) { if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent) && file.data.state == FS_OPEN) { #ifndef LINUX f_close(&file.data.handle); #else fclose(file.data.handle); file.data.handle = 0; #endif file.data.state = FS_CLOSED; fileSetVar(&file); // TODO: could try and free the memory used by file.data ? JsVar *arr = fsGetArray(false); if (arr) { JsVar *idx = jsvGetArrayIndexOf(arr, file.fileVar, true); if (idx) { jsvRemoveChild(arr, idx); jsvUnLock(idx); } jsvUnLock(arr); } } } } /*JSON{ "type" : "method", "class" : "File", "name" : "write", "generate" : "jswrap_file_write", "description" : [ "write data to a file"], "params" : [ ["buffer", "JsVar", "A string containing the bytes to write"] ], "return" : [ "int32", "the number of bytes written" ] }*/ size_t jswrap_file_write(JsVar* parent, JsVar* buffer) { FRESULT res = 0; size_t bytesWritten = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data.mode == FM_WRITE || file.data.mode == FM_READ_WRITE) { JsvIterator it; jsvIteratorNew(&it, buffer); char buf[32]; while (jsvIteratorHasElement(&it)) { // pull in a buffer's worth of data size_t n = 0; while (jsvIteratorHasElement(&it) && n<sizeof(buf)) { buf[n++] = (char)jsvIteratorGetIntegerValue(&it); jsvIteratorNext(&it); } // write it out size_t written = 0; #ifndef LINUX res = f_write(&file.data.handle, &buf, n, &written); #else written = fwrite(&buf, 1, n, file.data.handle); #endif bytesWritten += written; if(written == 0) res = FR_DISK_ERR; if (res) break; } jsvIteratorFree(&it); // finally, sync - just in case there's a reset or something #ifndef LINUX f_sync(&file.data.handle); #else fflush(file.data.handle); #endif } fileSetVar(&file); } } if (res) { jsfsReportError("Unable to write file", res); } return bytesWritten; }
/*JSON{ "type" : "staticmethod", "class" : "E", "name" : "openFile", "generate" : "jswrap_E_openFile", "params" : [ ["path","JsVar","the path to the file to open."], ["mode","JsVar","The mode to use when opening the file. Valid values for mode are 'r' for read, 'w' for write new, 'w+' for write existing, and 'a' for append. If not specified, the default is 'r'."] ], "return" : ["JsVar","A File object"], "return_object" : "File" } Open a file */ JsVar *jswrap_E_openFile(JsVar* path, JsVar* mode) { FRESULT res = FR_INVALID_NAME; JsFile file; file.data = 0; file.fileVar = 0; FileMode fMode = FM_NONE; if (jsfsInit()) { JsVar *arr = fsGetArray(true); if (!arr) return 0; // out of memory char pathStr[JS_DIR_BUF_SIZE] = ""; char modeStr[3] = "r"; if (!jsvIsUndefined(path)) { if (!jsfsGetPathString(pathStr, path)) { jsvUnLock(arr); return 0; } if (!jsvIsUndefined(mode)) jsvGetString(mode, modeStr, 3); #ifndef LINUX BYTE ff_mode = 0; bool append = false; #endif if(strcmp(modeStr,"r") == 0) { fMode = FM_READ; #ifndef LINUX ff_mode = FA_READ | FA_OPEN_EXISTING; #endif } else if(strcmp(modeStr,"a") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; append = true; #endif } else if(strcmp(modeStr,"w") == 0) { fMode = FM_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_CREATE_ALWAYS; #endif } else if(strcmp(modeStr,"w+") == 0) { fMode = FM_READ_WRITE; #ifndef LINUX ff_mode = FA_WRITE | FA_OPEN_ALWAYS; #endif } if(fMode != FM_NONE && allocateJsFile(&file, fMode, FT_FILE)) { #ifndef LINUX if ((res=f_open(&file.data->handle, pathStr, ff_mode)) == FR_OK) { if (append) f_lseek(&file.data->handle, file.data->handle.fsize); // move to end of file #else file.data->handle = fopen(pathStr, modeStr); if (file.data->handle) { res=FR_OK; #endif file.data->state = FS_OPEN; // add to list of open files jsvArrayPush(arr, file.fileVar); } else { // File open failed jsvUnLock(file.fileVar); file.fileVar = 0; } if(res != FR_OK) jsfsReportError("Could not open file", res); } } else { jsExceptionHere(JSET_ERROR,"Path is undefined"); } jsvUnLock(arr); } return file.fileVar; } /*JSON{ "type" : "method", "class" : "File", "name" : "close", "generate_full" : "jswrap_file_close(parent)" } Close an open file. */ void jswrap_file_close(JsVar* parent) { if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent) && file.data->state == FS_OPEN) { #ifndef LINUX f_close(&file.data->handle); #else fclose(file.data->handle); file.data->handle = 0; #endif file.data->state = FS_CLOSED; // TODO: could try and free the memory used by file.data ? JsVar *arr = fsGetArray(false); if (arr) { JsVar *idx = jsvGetIndexOf(arr, file.fileVar, true); if (idx) { jsvRemoveChild(arr, idx); jsvUnLock(idx); } jsvUnLock(arr); } } } } /*JSON{ "type" : "method", "class" : "File", "name" : "write", "generate" : "jswrap_file_write", "params" : [ ["buffer","JsVar","A string containing the bytes to write"] ], "return" : ["int32","the number of bytes written"] } Write data to a file. **Note:** By default this function flushes all changes to the SD card, which makes it slow (but also safe!). You can use `E.setFlags({unsyncFiles:1})` to disable this behaviour and really speed up writes - but then you must be sure to close all files you are writing before power is lost or you will cause damage to your SD card's filesystem. */ size_t jswrap_file_write(JsVar* parent, JsVar* buffer) { FRESULT res = 0; size_t bytesWritten = 0; if (jsfsInit()) { JsFile file; if (fileGetFromVar(&file, parent)) { if(file.data->mode == FM_WRITE || file.data->mode == FM_READ_WRITE) { JsvIterator it; jsvIteratorNew(&it, buffer, JSIF_EVERY_ARRAY_ELEMENT); char buf[32]; while (jsvIteratorHasElement(&it)) { // pull in a buffer's worth of data size_t n = 0; while (jsvIteratorHasElement(&it) && n<sizeof(buf)) { buf[n++] = (char)jsvIteratorGetIntegerValue(&it); jsvIteratorNext(&it); } // write it out size_t written = 0; #ifndef LINUX res = f_write(&file.data->handle, &buf, n, &written); #else written = fwrite(&buf, 1, n, file.data->handle); #endif bytesWritten += written; if(written == 0) res = FR_DISK_ERR; if (res) break; } jsvIteratorFree(&it); // finally, sync - just in case there's a reset or something if (!jsfGetFlag(JSF_UNSYNC_FILES)) { #ifndef LINUX f_sync(&file.data->handle); #else fflush(file.data->handle); #endif } } } } if (res) { jsfsReportError("Unable to write file", res); } return bytesWritten; }