/*JSON{ "type" : "method", "class" : "String", "name" : "split", "generate" : "jswrap_string_split", "params" : [ ["separator","JsVar","The start character index"] ], "return" : ["JsVar","Part of this string from start for len characters"] } Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==[1,2,3]``` */ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) { JsVar *array = jsvNewWithFlags(JSV_ARRAY); if (!array) return 0; // out of memory if (jsvIsUndefined(split)) { jsvArrayPush(array, parent); return array; } split = jsvAsString(split, false); int idx, last = 0; int splitlen = jsvIsUndefined(split) ? 0 : (int)jsvGetStringLength(split); int l = (int)jsvGetStringLength(parent) + 1 - splitlen; for (idx=0;idx<=l;idx++) { if (splitlen==0 && idx==0) continue; // special case for where split string is "" if (idx==l || splitlen==0 || jsvCompareString(parent, split, (size_t)idx, 0, true)==0) { if (idx==l) { idx=l+splitlen; // if the last element, do to the end of the string if (splitlen==0) break; } JsVar *part = jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last)); if (!part) break; // out of memory jsvArrayPush(array, part); jsvUnLock(part); last = idx+splitlen; } } jsvUnLock(split); return array; }
/*JSON{ "type" : "method", "class" : "Object", "name" : "on", "generate" : "jswrap_object_on", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to call when this event is received"] ] } Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter. */ void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.on(..) must be a string"); return; } if (!jsvIsFunction(listener) && !jsvIsString(listener)) { jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); return; } JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventList = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); JsVar *eventListeners = jsvSkipName(eventList); if (jsvIsUndefined(eventListeners)) { // just add jsvSetValueOfName(eventList, listener); } else { if (jsvIsArray(eventListeners)) { // we already have an array, just add to it jsvArrayPush(eventListeners, listener); } else { // not an array - we need to make it an array JsVar *arr = jsvNewEmptyArray(); jsvArrayPush(arr, eventListeners); jsvArrayPush(arr, listener); jsvSetValueOfName(eventList, arr); jsvUnLock(arr); } } jsvUnLock2(eventListeners, eventList); /* Special case if we're a data listener and data has already arrived then * we queue an event immediately. */ if (jsvIsStringEqual(event, "data")) { JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0); if (jsvIsString(buf)) { jsiQueueObjectCallbacks(parent, STREAM_CALLBACK_NAME, &buf, 1); jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME); } jsvUnLock(buf); } }
JsVar *clientRequestNew(SocketType socketType, JsVar *options, JsVar *callback) { JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,true); if (!arr) return 0; JsVar *req, *res = 0; if ((socketType&ST_TYPE_MASK)==ST_HTTP) { res = jspNewObject(0, "httpCRs"); if (!res) { jsvUnLock(arr); // out of memory? return 0; } req = jspNewObject(0, "httpCRq"); } else { req = jspNewObject(0, "Socket"); } if (req) { // out of memory? socketSetType(req, socketType); if (callback != NULL) jsvUnLock(jsvAddNamedChild(req, callback, HTTP_NAME_ON_CONNECT)); jsvArrayPush(arr, req); if (res) jsvObjectSetChild(req, HTTP_NAME_RESPONSE_VAR, res); jsvObjectSetChild(req, HTTP_NAME_OPTIONS_VAR, options); } jsvUnLock2(res, arr); return req; }
void httpIdle() { if (networkState != NETWORKSTATE_ONLINE) return; JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVERS,false); if (arr) { JsArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *server = jsvArrayIteratorGetElement(&it); SOCKET socket = (SOCKET)jsvGetIntegerAndUnLock(jsvObjectGetChild(server,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined #ifndef USE_CC3000 // TODO: look for unreffed servers? fd_set s; FD_ZERO(&s); FD_SET(socket,&s); // check for waiting clients struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 0; int n = select(socket+1,&s,NULL,NULL,&timeout); #else /* CC3000 works a different way - we set accept as nonblocking, * and then we just call it and see if it works or not... */ int n=1; #endif while (n-->0) { // we have a client waiting to connect... int theClient = accept(socket,NULL,NULL); // try and connect if (theClient > -1) { JsVar *req = jspNewObject(jsiGetParser(), 0, "httpSRq"); JsVar *res = jspNewObject(jsiGetParser(), 0, "httpSRs"); if (res && req) { // out of memory? JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS, true); if (arr) { jsvArrayPush(arr, req); jsvUnLock(arr); } jsvObjectSetChild(req, HTTP_NAME_RESPONSE_VAR, res); jsvObjectSetChild(req, HTTP_NAME_SERVER_VAR, server); jsvUnLock(jsvObjectSetChild(req, HTTP_NAME_SOCKET, jsvNewFromInteger(theClient+1))); // on response jsvUnLock(jsvObjectSetChild(res, HTTP_NAME_CODE, jsvNewFromInteger(200))); jsvUnLock(jsvObjectSetChild(res, HTTP_NAME_HEADERS, jsvNewWithFlags(JSV_OBJECT))); } jsvUnLock(req); jsvUnLock(res); //add(new CNetworkConnect(theClient, this)); // add to service queue } } jsvUnLock(server); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvUnLock(arr); } httpServerConnectionsIdle(); httpClientConnectionsIdle(); }
/*JSON{ "type" : "method", "class" : "Object", "name" : "on", "generate" : "jswrap_object_on", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to call when this event is received"] ] } Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter. */ void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.on(..) must be a string"); return; } if (!jsvIsFunction(listener) && !jsvIsString(listener)) { jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); return; } char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); JsVar *eventList = jsvFindChildFromString(parent, eventName, true); JsVar *eventListeners = jsvSkipName(eventList); if (jsvIsUndefined(eventListeners)) { // just add jsvSetValueOfName(eventList, listener); } else { if (jsvIsArray(eventListeners)) { // we already have an array, just add to it jsvArrayPush(eventListeners, listener); } else { // not an array - we need to make it an array JsVar *arr = jsvNewWithFlags(JSV_ARRAY); jsvArrayPush(arr, eventListeners); jsvArrayPush(arr, listener); jsvSetValueOfName(eventList, arr); jsvUnLock(arr); } } jsvUnLock(eventListeners); jsvUnLock(eventList); /* Special case if we're a data listener and data has already arrived then * we queue an event immediately. */ if (jsvIsStringEqual(event, "data")) { JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0); if (jsvIsString(buf)) { jsiQueueObjectCallbacks(parent, "#ondata", &buf, 1); jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME); } jsvUnLock(buf); } }
/*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "pipe", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_pipe", "params" : [ ["source","JsVar","The source file/stream that will send content."], ["destination","JsVar","The destination file/stream that will receive content from the source."], ["options","JsVar",["An optional object `{ chunkSize : int=64, end : bool=true, complete : function }`","chunkSize : The amount of data to pipe from source to destination at a time","complete : a function to call when the pipe activity is complete","end : call the 'end' function on the destination when the source is finished"]] ] }*/ void jswrap_pipe(JsVar* source, JsVar* dest, JsVar* options) { if (!source || !dest) return; JsVar *pipe = jspNewObject(0, "Pipe"); JsVar *arr = pipeGetArray(true); JsVar* position = jsvNewFromInteger(0); if (pipe && arr && position) {// out of memory? JsVar *readFunc = jspGetNamedField(source, "read", false); JsVar *writeFunc = jspGetNamedField(dest, "write", false); if(jsvIsFunction(readFunc)) { if(jsvIsFunction(writeFunc)) { JsVarInt chunkSize = 64; bool callEnd = true; // parse Options Object if (jsvIsObject(options)) { JsVar *c; c = jsvObjectGetChild(options, "complete", false); if (c) { jsvObjectSetChild(pipe, "#oncomplete", c); jsvUnLock(c); } c = jsvObjectGetChild(options, "end", false); if (c) callEnd = jsvGetBoolAndUnLock(c); c = jsvObjectGetChild(options, "chunkSize", false); if (c) { if (jsvIsNumeric(c) && jsvGetInteger(c)>0) chunkSize = jsvGetInteger(c); else jsWarn("chunkSize must be an integer > 0"); jsvUnLock(c); } } else if (!jsvIsUndefined(options)) { jsWarn("'options' must be an object, or undefined"); } // set up our event listeners jswrap_object_addEventListener(source, "close", jswrap_pipe_src_close_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1))); jswrap_object_addEventListener(dest, "drain", jswrap_pipe_drain_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1))); jswrap_object_addEventListener(dest, "close", jswrap_pipe_dst_close_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1))); // set up the rest of the pipe jsvUnLock(jsvObjectSetChild(pipe, "chunkSize", jsvNewFromInteger(chunkSize))); jsvUnLock(jsvObjectSetChild(pipe, "end", jsvNewFromBool(callEnd))); jsvUnLock(jsvAddNamedChild(pipe, position, "position")); jsvUnLock(jsvAddNamedChild(pipe, source, "source")); jsvUnLock(jsvAddNamedChild(pipe, dest, "destination")); // add the pipe to our list jsvArrayPush(arr, pipe); } else { jsExceptionHere(JSET_ERROR, "Destination object does not implement the required write(buffer, length, position) method."); } } else { jsExceptionHere(JSET_ERROR, "Source object does not implement the required read(buffer, length, position) method."); } jsvUnLock(readFunc); jsvUnLock(writeFunc); } jsvUnLock(arr); jsvUnLock(pipe); jsvUnLock(position); }
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); } }
void jswrap_promise_all_resolve(JsVar *promise, JsVar *data) { JsVarInt i = jsvGetIntegerAndUnLock(jsvObjectGetChild(promise, JS_PROMISE_COUNT_NAME, 0)); JsVar *arr = jsvObjectGetChild(promise, JS_PROMISE_RESULT_NAME, 0); if (arr) { // we may have already rejected... if (jsvArrayPush(arr, data) == i) { _jswrap_promise_queueresolve(promise, arr); } jsvUnLock(arr); } }
/*JSON{ "type" : "method", "class" : "String", "name" : "match", "generate" : "jswrap_string_match", "params" : [ ["subStr","JsVar","Substring or RegExp to match"] ], "return" : ["JsVar","This match array"] } Matches `subStr` occurrence in the string. */ JsVar *jswrap_string_match(JsVar *parent, JsVar *subStr) { if (!jsvIsString(parent)) return 0; if (jsvIsUndefined(subStr)) return 0; #ifndef SAVE_ON_FLASH // Use RegExp if one is passed in if (jsvIsInstanceOf(subStr, "RegExp")) { jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); JsVar *match; match = jswrap_regexp_exec(subStr, parent); if (!jswrap_regexp_hasFlag(subStr,'g')) { return match; } // global JsVar *array = jsvNewEmptyArray(); if (!array) return 0; // out of memory while (match && !jsvIsNull(match)) { // get info about match JsVar *matchStr = jsvGetArrayItem(match,0); JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0)); JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr); int last = idx+len; jsvArrayPushAndUnLock(array, matchStr); // search again jsvUnLock(match); jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(last)); match = jswrap_regexp_exec(subStr, parent); } jsvUnLock(match); jsvObjectSetChildAndUnLock(subStr, "lastIndex", jsvNewFromInteger(0)); return array; } #endif subStr = jsvAsString(subStr); int idx = jswrap_string_indexOf(parent, subStr, 0, false); if (idx>=0) { JsVar *array = jsvNewEmptyArray(); if (!array) { jsvUnLock(subStr); return 0; // out of memory } jsvArrayPush(array, subStr); jsvObjectSetChildAndUnLock(array, "index", jsvNewFromInteger(idx)); jsvObjectSetChildAndUnLock(array, "input", subStr); return array; } jsvUnLock(subStr); return NULL; }
/*JSON{ "type":"method", "class": "Object", "name" : "on", "description" : ["Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter."], "generate" : "jswrap_object_on", "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"], [ "listener", "JsVar", "The listener to call when this event is received"] ] }*/ void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.on(..) must be a string"); return; } if (!jsvIsFunction(listener) && !jsvIsString(listener)) { jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); return; } char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); JsVar *eventList = jsvFindChildFromString(parent, eventName, true); JsVar *eventListeners = jsvSkipName(eventList); if (jsvIsUndefined(eventListeners)) { // just add jsvSetValueOfName(eventList, listener); } else { if (jsvIsArray(eventListeners)) { // we already have an array, just add to it jsvArrayPush(eventListeners, listener); } else { // not an array - we need to make it an array JsVar *arr = jsvNewWithFlags(JSV_ARRAY); jsvArrayPush(arr, eventListeners); jsvArrayPush(arr, listener); jsvSetValueOfName(eventList, arr); jsvUnLock(arr); } } jsvUnLock(eventListeners); jsvUnLock(eventList); }
/*JSON{ "type" : "staticmethod", "class" : "ESP8266WiFi", "name" : "getConnectedStations", "generate" : "jswrap_ESP8266WiFi_getConnectedStations", "return" : ["JsVar","An array of connected stations."] }*/ JsVar *jswrap_ESP8266WiFi_getConnectedStations() { uint8 stationCount = wifi_softap_get_station_num(); struct station_info *stationInfo = wifi_softap_get_station_info(); JsVar *jsArray = jsvNewArray(NULL, 0); if (stationInfo != NULL) { while (stationInfo != NULL) { os_printf("Station IP: %d.%d.%d.%d\n", IP2STR(&(stationInfo->ip))); JsVar *jsStation = jsvNewWithFlags(JSV_OBJECT); jsvUnLock(jsvObjectSetChild(jsStation, "ip", jsvNewFromInteger(stationInfo->ip.addr))); jsvArrayPush(jsArray, jsStation); stationInfo = STAILQ_NEXT(stationInfo, next); } wifi_softap_free_station_info(); } return jsArray; }
/*JSON{ "type" : "method", "class" : "Array", "name" : "push", "generate" : "jswrap_array_push", "params" : [ ["arguments","JsVarArray","One or more arguments to add"] ], "return" : ["int","The new size of the array"] } Push a new value onto the end of this array' This is the opposite of `[1,2,3].unshift(0)`, which adds one or more elements to the beginning of the array. */ JsVarInt jswrap_array_push(JsVar *parent, JsVar *args) { if (!jsvIsArray(parent)) return -1; JsVarInt len = -1; JsvObjectIterator it; jsvObjectIteratorNew(&it, args); while (jsvObjectIteratorHasValue(&it)) { JsVar *el = jsvObjectIteratorGetValue(&it); len = jsvArrayPush(parent, el); jsvUnLock(el); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); if (len<0) len = jsvGetArrayLength(parent); return len; }
JsVar *httpClientRequestNew(JsVar *options, JsVar *callback) { JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,true); if (!arr) return 0; JsVar *req = jspNewObject(jsiGetParser(), 0, "httpCRq"); JsVar *res = jspNewObject(jsiGetParser(), 0, "httpCRs"); if (res && req) { // out of memory? jsvUnLock(jsvAddNamedChild(req, callback, HTTP_NAME_ON_CONNECT)); jsvArrayPush(arr, req); jsvObjectSetChild(req, HTTP_NAME_RESPONSE_VAR, res); jsvObjectSetChild(req, HTTP_NAME_OPTIONS_VAR, options); } jsvUnLock(res); jsvUnLock(arr); return req; }
void serverListen(JsNetwork *net, JsVar *server, int port) { JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVERS, true); if (!arr) return; // out of memory jsvObjectSetChildAndUnLock(server, HTTP_NAME_PORT, jsvNewFromInteger(port)); int sckt = netCreateSocket(net, 0/*server*/, (unsigned short)port, NCF_NORMAL, 0 /*options*/); if (sckt<0) { jsError("Unable to create socket\n"); jsvObjectSetChildAndUnLock(server, HTTP_NAME_CLOSENOW, jsvNewFromBool(true)); } else { jsvObjectSetChildAndUnLock(server, HTTP_NAME_SOCKET, jsvNewFromInteger(sckt+1)); // add to list of servers jsvArrayPush(arr, server); } jsvUnLock(arr); }
void _jswrap_promise_add(JsVar *parent, JsVar *callback, const char *name) { if (!jsvIsFunction(callback)) { jsExceptionHere(JSET_TYPEERROR, "Callback must be a function, got %t", callback); return; } JsVar *c = jsvObjectGetChild(parent, name, 0); if (!c) { jsvObjectSetChild(parent, name, callback); } else { if (jsvIsArray(c)) { jsvArrayPush(c, callback); } else { JsVar *fns[2] = {c,callback}; JsVar *arr = jsvNewArray(fns, 2); jsvObjectSetChild(parent, name, arr); jsvUnLock(arr); } jsvUnLock(c); } }
JsVar *httpServerNew(JsVar *callback) { SOCKET sckt = socket(AF_INET, // Go over TCP/IP SOCK_STREAM, // This is a stream-oriented socket IPPROTO_TCP); // Use TCP rather than UDP if (sckt == INVALID_SOCKET) { httpError("socket creation failed"); return 0; } JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVERS, true); if (!arr) return 0; // out of memory JsVar *server = jspNewObject(jsiGetParser(),0,"httpSrv"); if (!server) { jsvUnLock(arr); return 0; // out of memory } jsvObjectSetChild(server, HTTP_NAME_ON_CONNECT, callback); // no unlock needed jsvUnLock(jsvObjectSetChild(server, HTTP_NAME_SOCKET, jsvNewFromInteger(sckt+1))); #ifndef USE_CC3000 int optval = 1; if (setsockopt(sckt,SOL_SOCKET,SO_REUSEADDR,(const char *)&optval,sizeof(optval)) < 0) #else int optval = SOCK_ON; if (setsockopt(sckt,SOL_SOCKET,SOCKOPT_ACCEPT_NONBLOCK,(const char *)&optval,sizeof(optval)) < 0) #endif jsWarn("setsockopt failed\n"); // add to list of servers jsvArrayPush(arr, server); jsvUnLock(arr); return server; }
/*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; }
/** 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; }
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 } }
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 } } }
/*JSON{ "type":"method", "class": "Array", "name" : "splice", "description" : "Both remove and add items to an array", "generate" : "jswrap_array_splice", "params" : [ [ "index", "int", "Index at which to start changing the array. If negative, will begin that many elements from the end"], [ "howMany", "JsVar", "An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed."], [ "element1", "JsVar", "A new item to add (optional)" ], [ "element2", "JsVar", "A new item to add (optional)" ], [ "element3", "JsVar", "A new item to add (optional)" ], [ "element4", "JsVar", "A new item to add (optional)" ], [ "element5", "JsVar", "A new item to add (optional)" ], [ "element6", "JsVar", "A new item to add (optional)" ] ], "return" : ["JsVar", "An array containing the removed elements. If only one element is removed, an array of one element is returned."] }*/ JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *element1, JsVar *element2, JsVar *element3, JsVar *element4, JsVar *element5, JsVar *element6) { JsVarInt len = jsvGetArrayLength(parent); if (index<0) index+=len; if (index<0) index=0; if (index>len) index=len; JsVarInt howMany = len; // how many to delete! if (jsvIsInt(howManyVar)) howMany = jsvGetInteger(howManyVar); if (howMany > len-index) howMany = len-index; JsVarInt newItems = 0; if (element1) newItems++; if (element2) newItems++; if (element3) newItems++; if (element4) newItems++; if (element5) newItems++; if (element6) newItems++; JsVarInt shift = newItems-howMany; bool needToAdd = false; JsVar *result = jsvNewWithFlags(JSV_ARRAY); JsArrayIterator it; jsvArrayIteratorNew(&it, parent); while (jsvArrayIteratorHasElement(&it) && !needToAdd) { bool goToNext = true; JsVar *idxVar = jsvArrayIteratorGetIndex(&it); if (idxVar && jsvIsInt(idxVar)) { JsVarInt idx = jsvGetInteger(idxVar); if (idx<index) { // do nothing... } else if (idx<index+howMany) { // must delete if (result) { // append to result array JsVar *el = jsvArrayIteratorGetElement(&it); jsvArrayPush(result, el); jsvUnLock(el); } // delete goToNext = false; JsVar *toRemove = jsvArrayIteratorGetIndex(&it); jsvArrayIteratorNext(&it); jsvRemoveChild(parent, toRemove); jsvUnLock(toRemove); } else { // we're greater than the amount we need to remove now needToAdd = true; goToNext = false; } } jsvUnLock(idxVar); if (goToNext) jsvArrayIteratorNext(&it); } // now we add everything JsVar *beforeIndex = jsvArrayIteratorGetIndex(&it); if (element1) jsvArrayInsertBefore(parent, beforeIndex, element1); if (element2) jsvArrayInsertBefore(parent, beforeIndex, element2); if (element3) jsvArrayInsertBefore(parent, beforeIndex, element3); if (element4) jsvArrayInsertBefore(parent, beforeIndex, element4); if (element5) jsvArrayInsertBefore(parent, beforeIndex, element5); if (element6) jsvArrayInsertBefore(parent, beforeIndex, element6); jsvUnLock(beforeIndex); // And finally renumber while (jsvArrayIteratorHasElement(&it)) { JsVar *idxVar = jsvArrayIteratorGetIndex(&it); if (idxVar && jsvIsInt(idxVar)) { jsvSetInteger(idxVar, jsvGetInteger(idxVar)+shift); } jsvUnLock(idxVar); jsvArrayIteratorNext(&it); } // free jsvArrayIteratorFree(&it); return result; }
/*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" : "method", "class" : "String", "name" : "split", "generate" : "jswrap_string_split", "params" : [ ["separator","JsVar","The separator `String` or `RegExp` to use"] ], "return" : ["JsVar","Part of this string from start for len characters"] } Return an array made by splitting this string up by the separator. eg. ```'1,2,3'.split(',')==['1', '2', '3']``` Regular Expressions can also be used to split strings, eg. `'1a2b3 4'.split(/[^0-9]/)==['1', '2', '3', '4']`. */ JsVar *jswrap_string_split(JsVar *parent, JsVar *split) { if (!jsvIsString(parent)) return 0; JsVar *array = jsvNewEmptyArray(); if (!array) return 0; // out of memory if (jsvIsUndefined(split)) { jsvArrayPush(array, parent); return array; } #ifndef SAVE_ON_FLASH // Use RegExp if one is passed in if (jsvIsInstanceOf(split, "RegExp")) { unsigned int last = 0; JsVar *match; jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0)); match = jswrap_regexp_exec(split, parent); while (match && !jsvIsNull(match)) { // get info about match JsVar *matchStr = jsvGetArrayItem(match,0); JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectGetChild(match,"index",0)); JsVarInt len = (JsVarInt)jsvGetStringLength(matchStr); jsvUnLock(matchStr); // do the replacement jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last))); last = idx+len; // search again jsvUnLock(match); jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(last)); match = jswrap_regexp_exec(split, parent); } jsvUnLock(match); jsvObjectSetChildAndUnLock(split, "lastIndex", jsvNewFromInteger(0)); // add remaining string after last match if (last<=jsvGetStringLength(parent)) jsvArrayPushAndUnLock(array, jsvNewFromStringVar(parent, (size_t)last, JSVAPPENDSTRINGVAR_MAXLENGTH)); return array; } #endif split = jsvAsString(split); int idx, last = 0; int splitlen = jsvIsUndefined(split) ? 0 : (int)jsvGetStringLength(split); int l = (int)jsvGetStringLength(parent) + 1 - splitlen; for (idx=0;idx<=l;idx++) { if (splitlen==0 && idx==0) continue; // special case for where split string is "" if (idx==l || splitlen==0 || jsvCompareString(parent, split, (size_t)idx, 0, true)==0) { if (idx==l) { idx=l+splitlen; // if the last element, do to the end of the string if (splitlen==0) break; } JsVar *part = jsvNewFromStringVar(parent, (size_t)last, (size_t)(idx-last)); if (!part) break; // out of memory jsvArrayPush(array, part); jsvUnLock(part); last = idx+splitlen; } } jsvUnLock(split); return array; }
JsVar *jswrap_fs_readdir(JsVar *path) { JsVar *arr = 0; // undefined unless we can open card char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); #ifdef LINUX if (!pathStr[0]) strcpy(pathStr, "."); // deal with empty readdir #endif FRESULT res = 0; if (jsfsInit()) { #ifndef LINUX DIR dirs; if ((res=f_opendir(&dirs, pathStr)) == FR_OK) { FILINFO Finfo; #if _USE_LFN!=0 char lfnBuf[_MAX_LFN+1]; Finfo.lfname = lfnBuf; Finfo.lfsize = sizeof(lfnBuf); #endif #else DIR *dir = opendir(pathStr); if(dir) { #endif arr = jsvNewWithFlags(JSV_ARRAY); if (arr) { // could be out of memory #ifndef LINUX while (((res=f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) { char *fn = GET_FILENAME(Finfo); #else struct dirent *pDir=NULL; while((pDir = readdir(dir)) != NULL) { char *fn = (*pDir).d_name; #endif JsVar *fnVar = jsvNewFromString(fn); if (fnVar) {// out of memory? jsvArrayPush(arr, fnVar); jsvUnLock(fnVar); } } } #ifdef LINUX closedir(dir); #endif } } if (res) jsfsReportError("Unable to list files", res); return arr; } /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "writeFile", "generate_full" : " jswrap_fs_writeOrAppendFile(path, data, false)", "description" : [ "Write the data to the given file", "NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version." ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ], "return" : [ "bool", "True on success, false on failure" ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "writeFileSync", "ifndef" : "SAVE_ON_FLASH", "generate_full" : " jswrap_fs_writeOrAppendFile(path, data, false)", "description" : [ "Write the data to the given file" ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ], "return" : [ "bool", "True on success, false on failure" ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "appendFile", "generate_full" : " jswrap_fs_writeOrAppendFile(path, data, true)", "description" : [ "Append the data to the given file, created a new file if it doesn't exist", "NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version." ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ], "return" : [ "bool", "True on success, false on failure" ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "appendFileSync", "ifndef" : "SAVE_ON_FLASH", "generate_full" : "jswrap_fs_writeOrAppendFile(path, data, true)", "description" : [ "Append the data to the given file, created a new file if it doesn't exist" ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ], "return" : [ "bool", "True on success, false on failure" ] }*/ bool jswrap_fs_writeOrAppendFile(JsVar *path, JsVar *data, bool append) { JsVar *fMode = jsvNewFromString(append ? "a" : "w"); JsVar *f = jswrap_E_openFile(path, fMode); jsvUnLock(fMode); if (!f) return 0; size_t amt = jswrap_file_write(f, data); jswrap_file_close(f); jsvUnLock(f); return amt>0; } /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "readFile", "generate" : "jswrap_fs_readFile", "description" : [ "Read all data from a file and return as a string", "NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version." ], "params" : [ [ "path", "JsVar", "The path of the file to read" ] ], "return" : [ "JsVar", "A string containing the contents of the file (or undefined if the file doesn't exist)" ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "readFileSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_fs_readFile", "description" : [ "Read all data from a file and return as a string.","**Note:** The size of files you can load using this method is limited by the amount of available RAM. To read files a bit at a time, see the `File` class." ], "params" : [ [ "path", "JsVar", "The path of the file to read" ] ], "return" : [ "JsVar", "A string containing the contents of the file (or undefined if the file doesn't exist)" ] }*/ JsVar *jswrap_fs_readFile(JsVar *path) { JsVar *fMode = jsvNewFromString("r"); JsVar *f = jswrap_E_openFile(path, fMode); jsvUnLock(fMode); if (!f) return 0; JsVar *buffer = jswrap_file_read(f, 0x7FFFFFFF); jswrap_file_close(f); jsvUnLock(f); return buffer; }
bool socketIdle(JsNetwork *net) { if (networkState != NETWORKSTATE_ONLINE) { // clear all clients and servers _socketCloseAllConnections(net); return false; } bool hadSockets = false; JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVERS,false); if (arr) { JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { hadSockets = true; JsVar *server = jsvObjectIteratorGetValue(&it); int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(server,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined int theClient = netAccept(net, sckt); if (theClient >= 0) { SocketType socketType = socketGetType(server); if ((socketType&ST_TYPE_MASK) == ST_HTTP) { JsVar *req = jspNewObject(0, "httpSRq"); JsVar *res = jspNewObject(0, "httpSRs"); if (res && req) { // out of memory? socketSetType(req, ST_HTTP); JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS, true); if (arr) { jsvArrayPush(arr, req); jsvUnLock(arr); } jsvObjectSetChild(req, HTTP_NAME_RESPONSE_VAR, res); jsvObjectSetChild(req, HTTP_NAME_SERVER_VAR, server); jsvObjectSetChildAndUnLock(req, HTTP_NAME_SOCKET, jsvNewFromInteger(theClient+1)); } jsvUnLock2(req, res); } else { // Normal sockets JsVar *sock = jspNewObject(0, "Socket"); if (sock) { // out of memory? socketSetType(sock, ST_NORMAL); JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS, true); if (arr) { jsvArrayPush(arr, sock); jsvUnLock(arr); } jsvObjectSetChildAndUnLock(sock, HTTP_NAME_SOCKET, jsvNewFromInteger(theClient+1)); jsiQueueObjectCallbacks(server, HTTP_NAME_ON_CONNECT, &sock, 1); jsvUnLock(sock); } } } jsvUnLock(server); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(arr); } if (socketServerConnectionsIdle(net)) hadSockets = true; if (socketClientConnectionsIdle(net)) hadSockets = true; netCheckError(net); return hadSockets; }
/** 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) { 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; } }
JsVar *wrap_fat_readdir(JsVar *path) { JsVar *arr = 0; // undefined unless we can open card char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); #ifdef LINUX if (!pathStr[0]) strcpy(pathStr, "."); // deal with empty readdir #endif FRESULT res = 0; if (jsfsInit()) { #ifndef LINUX DIR dirs; if ((res=f_opendir(&dirs, pathStr)) == FR_OK) { char lfnBuf[_MAX_LFN+1]; FILINFO Finfo; Finfo.lfname = lfnBuf; Finfo.lfsize = sizeof(lfnBuf); #else DIR *dir = opendir(pathStr); if(dir) { #endif arr = jsvNewWithFlags(JSV_ARRAY); if (arr) { // could be out of memory #ifndef LINUX while (((res=f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) { char *fn = GET_FILENAME(Finfo); #else struct dirent *pDir=NULL; while((pDir = readdir(dir)) != NULL) { char *fn = (*pDir).d_name; #endif JsVar *fnVar = jsvNewFromString(fn); if (fnVar) // out of memory? jsvArrayPush(arr, fnVar); } } #ifdef LINUX closedir(dir); #endif } } if (res) jsfsReportError("Unable to list files", res); return arr; } /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "writeFile", "generate" : "wrap_fat_writeFile", "description" : [ "Write the data to the given file", "NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version." ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "writeFileSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "wrap_fat_writeFile", "description" : [ "Write the data to the given file" ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "appendFile", "generate" : "wrap_fat_appendFile", "description" : [ "Append the data to the given file, created a new file if it doesn't exist", "NOTE: Espruino does not yet support Async file IO, so this function behaves like the 'Sync' version." ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ /*JSON{ "type" : "staticmethod", "class" : "fs", "name" : "appendFileSync", "ifndef" : "SAVE_ON_FLASH", "generate" : "wrap_fat_appendFile", "description" : [ "Append the data to the given file, created a new file if it doesn't exist" ], "params" : [ [ "path", "JsVar", "The path of the file to write" ], [ "data", "JsVar", "The data to write to the file" ] ] }*/ void wrap_fat_writeOrAppendFile(JsVar *path, JsVar *data, bool append) { char pathStr[JS_DIR_BUF_SIZE] = ""; if (!jsvIsUndefined(path)) jsvGetString(path, pathStr, JS_DIR_BUF_SIZE); FRESULT res = 0; if (jsfsInit()) { #ifndef LINUX FIL file; if ((res=f_open(&file, pathStr, FA_WRITE|(append ? FA_OPEN_ALWAYS : FA_CREATE_ALWAYS))) == FR_OK) { if (append) { // move to end of file to append data f_lseek(&file, file.fsize); // if (res != FR_OK) jsfsReportError("Unable to move to end of file", res); } #else FILE *file = fopen(pathStr, append?"a":"w"); if (file) { #endif JsvStringIterator it; JsVar *dataString = jsvAsString(data, false); jsvStringIteratorNew(&it, dataString, 0); size_t toWrite = 0; size_t written = 0; while (jsvStringIteratorHasChar(&it) && res==FR_OK && written==toWrite) { // re-use pathStr buffer toWrite = 0; while (jsvStringIteratorHasChar(&it) && toWrite < JS_DIR_BUF_SIZE) { pathStr[toWrite++] = jsvStringIteratorGetChar(&it); jsvStringIteratorNext(&it); } #ifndef LINUX res = f_write(&file, pathStr, toWrite, &written); #else written = fwrite(pathStr, 1, toWrite, file); #endif } jsvStringIteratorFree(&it); jsvUnLock(dataString); #ifndef LINUX f_close(&file); #else fclose(file); #endif } } if (res) jsfsReportError("Unable to write file", res); } void wrap_fat_writeFile(JsVar *path, JsVar *data) { wrap_fat_writeOrAppendFile(path, data, false); } void wrap_fat_appendFile(JsVar *path, JsVar *data) { wrap_fat_writeOrAppendFile(path, data, true); }
/** * Callback function that is invoked at the culmination of a scan. */ static void scanCB(void *arg, STATUS status) { /** * Create a JsVar that is an array of JS objects where each JS object represents a * retrieved access point set of information. The structure of a record will be: * o authMode * o isHidden * o rssi * o channel * o ssid * When the array has been built, invoke the callback function passing in the array * of records. */ os_printf(">> scanCB\n"); // Create the Empty JS array that will be passed as a parameter to the callback. JsVar *accessPointArray = jsvNewArray(NULL, 0); struct bss_info *bssInfo; bssInfo = (struct bss_info *)arg; while(bssInfo != NULL) { // Add a new object to the JS array that will be passed as a parameter to // the callback. The ESP8266 bssInfo structure contains the following: // --- // uint8 bssid[6] // uint8 ssid[32] // uint8 channel // sint8 rssi \96 The received signal strength indication // AUTH_MODE authmode // Open = 0 // WEP = 1 // WPA_PSK = 2 // WPA2_PSK = 3 // WPA_WPA2_PSK = 4 // uint8 is_hidden // sint16 freq_offset // --- // Create, populate and add a child ... JsVar *currentAccessPoint = jspNewObject(NULL, "AccessPoint"); jsvUnLock(jsvObjectSetChild(currentAccessPoint, "rssi", jsvNewFromInteger(bssInfo->rssi))); jsvUnLock(jsvObjectSetChild(currentAccessPoint, "channel", jsvNewFromInteger(bssInfo->channel))); jsvUnLock(jsvObjectSetChild(currentAccessPoint, "authMode", jsvNewFromInteger(bssInfo->authmode))); jsvUnLock(jsvObjectSetChild(currentAccessPoint, "isHidden", jsvNewFromBool(bssInfo->is_hidden))); // The SSID may **NOT** be NULL terminated ... so handle that. char ssid[sizeof(bssInfo->ssid) + 1]; os_strncpy((char *)ssid, (char *)bssInfo->ssid, sizeof(bssInfo->ssid)); ssid[sizeof(ssid)-1] = '\0'; jsvUnLock(jsvObjectSetChild(currentAccessPoint, "ssid", jsvNewFromString(ssid))); // Add the new record to the array jsvArrayPush(accessPointArray, currentAccessPoint); os_printf(" - ssid: %s\n", bssInfo->ssid); bssInfo = STAILQ_NEXT(bssInfo, next); } // We have now completed the scan callback, so now we can invoke the JS callback. JsVar *params[1]; params[0] = accessPointArray; jsiQueueEvents(NULL, g_jsScanCallback, params, 1); jsvUnLock(g_jsScanCallback); os_printf("<< scanCB\n"); }