/*JSON{ "type" : "method", "class" : "Pin", "name" : "getInfo", "ifndef" : "SAVE_ON_FLASH", "generate" : "jswrap_pin_getInfo", "return" : ["JsVar","An object containing information about this pins"] } Get information about this pin and its capabilities. Of the form: ``` { "port" : "A", // the Pin's port on the chip "num" : 12, // the Pin's number "in_addr" : 0x..., // (if available) the address of the pin's input address in bit-banded memory (can be used with peek) "out_addr" : 0x..., // (if available) the address of the pin's output address in bit-banded memory (can be used with poke) "analog" : { ADCs : [1], channel : 12 }, // If analog input is available "functions" : { "TIM1":{type:"CH1, af:0}, "I2C3":{type:"SCL", af:1} } } ``` Will return undefined if pin is not valid. */ JsVar *jswrap_pin_getInfo( JsVar *parent //!< The class instance representing the pin. ) { Pin pin = jshGetPinFromVar(parent); if (!jshIsPinValid(pin)) return 0; const JshPinInfo *inf = &pinInfo[pin]; JsVar *obj = jsvNewObject(); if (!obj) return 0; char buf[2]; buf[0] = (char)('A'+(inf->port-JSH_PORTA)); buf[1] = 0; jsvObjectSetChildAndUnLock(obj, "port", jsvNewFromString(buf)); jsvObjectSetChildAndUnLock(obj, "num", jsvNewFromInteger(inf->pin-JSH_PIN0)); #ifdef STM32 volatile uint32_t *addr; addr = jshGetPinAddress(pin, JSGPAF_INPUT); if (addr) jsvObjectSetChildAndUnLock(obj, "in_addr", jsvNewFromInteger((JsVarInt)addr)); addr = jshGetPinAddress(pin, JSGPAF_OUTPUT); if (addr) jsvObjectSetChildAndUnLock(obj, "out_addr", jsvNewFromInteger((JsVarInt)addr)); #endif // ADC if (inf->analog) { JsVar *an = jsvNewObject(); if (an) { JsVar *arr = jsvNewEmptyArray(); if (arr) { int i; for (i=0; i<ADC_COUNT; i++) if (inf->analog&(JSH_ANALOG1<<i)) jsvArrayPushAndUnLock(arr, jsvNewFromInteger(1+i)); jsvObjectSetChildAndUnLock(an, "ADCs", arr); } jsvObjectSetChildAndUnLock(obj, "channel", jsvNewFromInteger(inf->analog & JSH_MASK_ANALOG_CH)); } } JsVar *funcs = jsvNewObject(); if (funcs) { int i; for (i=0; i<JSH_PININFO_FUNCTIONS; i++) { if (inf->functions[i]) { JsVar *func = jsvNewObject(); if (func) { char buf[16]; jshPinFunctionToString(inf->functions[i], JSPFTS_TYPE, buf, sizeof(buf)); jsvObjectSetChildAndUnLock(func, "type", jsvNewFromString(buf)); jsvObjectSetChildAndUnLock(func, "af", jsvNewFromInteger(inf->functions[i] & JSH_MASK_AF)); jshPinFunctionToString(inf->functions[i], JSPFTS_DEVICE|JSPFTS_DEVICE_NUMBER, buf, sizeof(buf)); jsvObjectSetChildAndUnLock(funcs, buf, func); } } } jsvObjectSetChildAndUnLock(obj, "functions", funcs); } return obj; }
/*JSON{ "type" : "staticmethod", "class" : "Object", "name" : "getOwnPropertyDescriptor", "generate" : "jswrap_object_getOwnPropertyDescriptor", "params" : [ ["obj","JsVar","The object"], ["name","JsVar","The name of the property"] ], "return" : ["JsVar","An object with a description of the property. The values of writable/enumerable/configurable may not be entirely correct due to Espruino's implementation."] } Get information on the given property in the object, or undefined */ JsVar *jswrap_object_getOwnPropertyDescriptor(JsVar *parent, JsVar *name) { if (!jswrap_object_hasOwnProperty(parent, name)) return 0; JsVar *propName = jsvAsArrayIndex(name); JsVar *varName = jspGetVarNamedField(parent, propName, true); jsvUnLock(propName); assert(varName); // we had it! (apparently) if (!varName) return 0; JsVar *obj = jsvNewObject(); if (!obj) { jsvUnLock(varName); return 0; } //jsvTrace(varName, 5); JsVar *var = jsvSkipName(varName); bool isBuiltIn = jsvIsNewChild(varName); JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(parent); jsvObjectSetChild(obj, "value", var); jsvObjectSetChildAndUnLock(obj, "writable", jsvNewFromBool(true)); jsvObjectSetChildAndUnLock(obj, "enumerable", jsvNewFromBool(!checkerFunction || !checkerFunction(varName))); jsvObjectSetChildAndUnLock(obj, "configurable", jsvNewFromBool(!isBuiltIn)); jsvUnLock2(var, varName); return obj; }
/*JSON{ "type" : "function", "name" : "setTimeout", "generate" : "jswrap_interface_setTimeout", "params" : [ ["function","JsVar","A Function or String to be executed"], ["timeout","float","The time until the function will be executed"], ["args","JsVarArray","Optional arguments to pass to the function when executed"] ], "return" : ["JsVar","An ID that can be passed to clearTimeout"] } Call the function (or evaluate the string) specified ONCE after the timeout in milliseconds. For instance: ``` setTimeout(function () { console.log("Hello World"); }, 1000); // or setTimeout('console.log("Hello World");', 1000); // both print 'Hello World' after a second ``` You can also specify extra arguments that will be sent to the function when it is executed. For example: ``` setTimeout(function (a,b) { console.log(a+" "+b); }, 1000, "Hello", "World"); // prints 'Hello World' after 1 second ``` If you want to stop the function from being called, pass the number that was returned by `setTimeout` into the `clearInterval` function. **Note:** If `setDeepSleep(true)` has been called and the interval is greater than 5 seconds, Espruino may execute the interval up to 1 second late. This is because Espruino can only wake from deep sleep every second - and waking early would cause Espruino to waste power while it waited for the correct time. */ JsVar *_jswrap_interface_setTimeoutOrInterval(JsVar *func, JsVarFloat interval, JsVar *args, bool isTimeout) { // NOTE: The 5 sec delay mentioned in the description is handled by jshSleep JsVar *itemIndex = 0; if (!jsvIsFunction(func) && !jsvIsString(func)) { jsExceptionHere(JSET_ERROR, "Function or String not supplied!"); } else { // Create a new timer JsVar *timerPtr = jsvNewObject(); if (interval<TIMER_MIN_INTERVAL) interval=TIMER_MIN_INTERVAL; JsSysTime intervalInt = jshGetTimeFromMilliseconds(interval); jsvObjectSetChildAndUnLock(timerPtr, "time", jsvNewFromLongInteger((jshGetSystemTime() - jsiLastIdleTime) + intervalInt)); if (!isTimeout) { jsvObjectSetChildAndUnLock(timerPtr, "interval", jsvNewFromLongInteger(intervalInt)); } jsvObjectSetChild(timerPtr, "callback", func); // intentionally no unlock if (jsvGetArrayLength(args)) jsvObjectSetChild(timerPtr, "args", args); // intentionally no unlock // Add to array itemIndex = jsvNewFromInteger(jsiTimerAdd(timerPtr)); jsvUnLock(timerPtr); jsiTimersChanged(); // mark timers as changed } return itemIndex; }
/*JSON{ "type" : "staticmethod", "class" : "process", "name" : "memory", "generate" : "jswrap_process_memory", "return" : ["JsVar","Information about memory usage"] } Run a Garbage Collection pass, and return an object containing information on memory usage. * `free` : Memory that is available to be used (in blocks) * `usage` : Memory that has been used (in blocks) * `total` : Total memory (in blocks) * `history` : Memory used for command history - that is freed if memory is low. Note that this is INCLUDED in the figure for 'free' * `gc` : Memory freed during the GC pass * `gctime` : Time taken for GC pass (in milliseconds) * `stackEndAddress` : (on ARM) the address (that can be used with peek/poke/etc) of the END of the stack. The stack grows down, so unless you do a lot of recursion the bytes above this can be used. * `flash_start` : (on ARM) the address of the start of flash memory (usually `0x8000000`) * `flash_binary_end` : (on ARM) the address in flash memory of the end of Espruino's firmware. * `flash_code_start` : (on ARM) the address in flash memory of pages that store any code that you save with `save()`. * `flash_length` : (on ARM) the amount of flash memory this firmware was built for (in bytes). **Note:** Some STM32 chips actually have more memory than is advertised. Memory units are specified in 'blocks', which are around 16 bytes each (depending on your device). See http://www.espruino.com/Performance for more information. **Note:** To find free areas of flash memory, see `require('Flash').getFree()` */ JsVar *jswrap_process_memory() { JsSysTime time1 = jshGetSystemTime(); int gc = jsvGarbageCollect(); JsSysTime time2 = jshGetSystemTime(); JsVar *obj = jsvNewObject(); if (obj) { unsigned int history = 0; JsVar *historyVar = jsvObjectGetChild(execInfo.hiddenRoot, JSI_HISTORY_NAME, 0); if (historyVar) { history = (unsigned int)jsvCountJsVarsUsed(historyVar); // vars used to store history jsvUnLock(historyVar); } unsigned int usage = jsvGetMemoryUsage() - history; unsigned int total = jsvGetMemoryTotal(); jsvObjectSetChildAndUnLock(obj, "free", jsvNewFromInteger((JsVarInt)(total-usage))); jsvObjectSetChildAndUnLock(obj, "usage", jsvNewFromInteger((JsVarInt)usage)); jsvObjectSetChildAndUnLock(obj, "total", jsvNewFromInteger((JsVarInt)total)); jsvObjectSetChildAndUnLock(obj, "history", jsvNewFromInteger((JsVarInt)history)); jsvObjectSetChildAndUnLock(obj, "gc", jsvNewFromInteger((JsVarInt)gc)); jsvObjectSetChildAndUnLock(obj, "gctime", jsvNewFromFloat(jshGetMillisecondsFromTime(time2-time1))); #ifdef ARM extern uint32_t LINKER_END_VAR; // end of ram used (variables) - should be 'void', but 'int' avoids warnings extern uint32_t LINKER_ETEXT_VAR; // end of flash text (binary) section - should be 'void', but 'int' avoids warnings jsvObjectSetChildAndUnLock(obj, "stackEndAddress", jsvNewFromInteger((JsVarInt)(unsigned int)&LINKER_END_VAR)); jsvObjectSetChildAndUnLock(obj, "flash_start", jsvNewFromInteger((JsVarInt)FLASH_START)); jsvObjectSetChildAndUnLock(obj, "flash_binary_end", jsvNewFromInteger((JsVarInt)(unsigned int)&LINKER_ETEXT_VAR)); jsvObjectSetChildAndUnLock(obj, "flash_code_start", jsvNewFromInteger((JsVarInt)FLASH_SAVED_CODE_START)); jsvObjectSetChildAndUnLock(obj, "flash_length", jsvNewFromInteger((JsVarInt)FLASH_TOTAL)); #endif } return obj; }
/*JSON{ "type" : "method", "class" : "WLAN", "name" : "getIP", "generate" : "jswrap_wlan_getIP", "return" : ["JsVar",""] } Get the current IP address */ JsVar *jswrap_wlan_getIP(JsVar *wlanObj) { NOT_USED(wlanObj); if (networkState != NETWORKSTATE_ONLINE) { jsError("Not connected to the internet"); return 0; } JsNetwork net; if (!networkGetFromVar(&net)) return 0; tNetappIpconfigRetArgs ipconfig; netapp_ipconfig(&ipconfig); networkFree(&net); /* If byte 1 is 0 we don't have a valid address */ if (ipconfig.aucIP[3] == 0) return 0; JsVar *data = jsvNewObject(); networkPutAddressAsString(data, "ip", &ipconfig.aucIP[0], -4, 10, '.'); networkPutAddressAsString(data, "subnet", &ipconfig.aucSubnetMask[0], -4, 10, '.'); networkPutAddressAsString(data, "gateway", &ipconfig.aucDefaultGateway[0], -4, 10, '.'); networkPutAddressAsString(data, "dhcp", &ipconfig.aucDHCPServer[0], -4, 10, '.'); networkPutAddressAsString(data, "dns", &ipconfig.aucDNSServer[0], -4, 10, '.'); networkPutAddressAsString(data, "mac", &ipconfig.uaMacAddr[0], -6, 16, 0); return data; }
/*JSON{ "type" : "staticmethod", "class" : "ESP32", "name" : "getState", "generate" : "jswrap_ESP32_getState", "return" : ["JsVar", "The state of the ESP32"] } Returns an object that contains details about the state of the ESP32 with the following fields: * `sdkVersion` - Version of the SDK. * `cpuFrequency` - CPU operating frequency in Mhz. * `freeHeap` - Amount of free heap in bytes. * `maxCon` - Maximum number of concurrent connections. * `flashMap` - Configured flash size&map: '512KB:256/256' .. '4MB:512/512' * `flashKB` - Configured flash size in KB as integer * `flashChip` - Type of flash chip as string with manufacturer & chip, ex: '0xEF 0x4016` */ JsVar *jswrap_ESP32_getState() { // Create a new variable and populate it with the properties of the ESP32 that we // wish to return. JsVar *esp32State = jsvNewObject(); // system_get_sdk_version() - is deprecated , need to find alternative jsvObjectSetChildAndUnLock(esp32State, "sdkVersion", jsvNewFromString("1.0 2016-12-03")); //jsvObjectSetChildAndUnLock(esp32State, "cpuFrequency", jsvNewFromInteger(system_get_cpu_freq())); jsvObjectSetChildAndUnLock(esp32State, "freeHeap", jsvNewFromInteger(esp_get_free_heap_size())); return esp32State; } // End of jswrap_ESP32_getState
/*JSON{ "type" : "constructor", "class" : "Object", "name" : "Object", "generate" : "jswrap_object_constructor", "params" : [ ["value","JsVar","A single value to be converted to an object"] ], "return" : ["JsVar","An Object"] } Creates an Object from the supplied argument */ JsVar *jswrap_object_constructor(JsVar *value) { if (jsvIsObject(value) || jsvIsArray(value) || jsvIsFunction(value)) return jsvLockAgain(value); const char *objName = jswGetBasicObjectName(value); JsVar *funcName = objName ? jspGetNamedVariable(objName) : 0; if (!funcName) return jsvNewObject(); JsVar *func = jsvSkipName(funcName); JsVar *result = jspeFunctionCall(func, funcName, 0, false, 1, &value); jsvUnLock2(funcName, func); return result; }
/*JSON{ "type" : "staticmethod", "class" : "Object", "name" : "create", "generate" : "jswrap_object_create", "params" : [ ["proto","JsVar","A prototype object"], ["propertiesObject","JsVar","An object containing properties. NOT IMPLEMENTED"] ], "return" : ["JsVar","A new object"] } Creates a new object with the specified prototype object and properties. properties are currently unsupported. */ JsVar *jswrap_object_create(JsVar *proto, JsVar *propertiesObject) { if (!jsvIsObject(proto) && !jsvIsNull(proto)) { jsWarn("Object prototype may only be an Object or null: %t", proto); return 0; } if (jsvIsObject(propertiesObject)) { jsWarn("propertiesObject is not supported yet"); } JsVar *obj = jsvNewObject(); if (!obj) return 0; if (jsvIsObject(proto)) jsvObjectSetChild(obj, JSPARSE_INHERITS_VAR, proto); return obj; }
// Fire error events on up to two objects if there is an error, returns true if there is an error // The error events have a code field and a message field. static bool fireErrorEvent(int error, JsVar *obj1, JsVar *obj2) { bool hadError = error < 0 && error != SOCKET_ERR_CLOSED; JsVar *params[1]; if (hadError) { params[0] = jsvNewObject(); jsvObjectSetChildAndUnLock(params[0], "code", jsvNewFromInteger(error)); jsvObjectSetChildAndUnLock(params[0], "message", jsvNewFromString(socketErrorString(error))); if (obj1 != NULL) jsiQueueObjectCallbacks(obj1, HTTP_NAME_ON_ERROR, params, 1); if (obj2 != NULL) jsiQueueObjectCallbacks(obj2, HTTP_NAME_ON_ERROR, params, 1); jsvUnLock(params[0]); } return hadError; }
/*JSON{ "type" : "staticproperty", "class" : "process", "name" : "env", "generate" : "jswrap_process_env", "return" : ["JsVar","An object"] } Returns an Object containing various pre-defined variables. standard ones are BOARD, VERSION, FLASH, RAM, MODULES. For example, to get a list of built-in modules, you can use `process.env.MODULES.split(',')` */ JsVar *jswrap_process_env() { JsVar *obj = jsvNewObject(); jsvObjectSetChildAndUnLock(obj, "VERSION", jsvNewFromString(JS_VERSION)); #ifdef GIT_COMMIT jsvObjectSetChildAndUnLock(obj, "GIT_COMMIT", jsvNewFromString(STRINGIFY(GIT_COMMIT))); #endif jsvObjectSetChildAndUnLock(obj, "BOARD", jsvNewFromString(PC_BOARD_ID)); jsvObjectSetChildAndUnLock(obj, "FLASH", jsvNewFromInteger(FLASH_TOTAL)); jsvObjectSetChildAndUnLock(obj, "RAM", jsvNewFromInteger(RAM_TOTAL)); jsvObjectSetChildAndUnLock(obj, "SERIAL", jswrap_interface_getSerial()); jsvObjectSetChildAndUnLock(obj, "CONSOLE", jsvNewFromString(jshGetDeviceString(jsiGetConsoleDevice()))); jsvObjectSetChildAndUnLock(obj, "MODULES", jsvNewFromString(jswGetBuiltInLibraryNames())); #ifndef SAVE_ON_FLASH // Pointer to a list of predefined exports - eventually we'll get rid of the array above jsvObjectSetChildAndUnLock(obj, "EXPTR", jsvNewFromInteger((JsVarInt)(size_t)exportPtrs)); #endif return obj; }
/*JSON{ "type" : "method", "class" : "Ethernet", "name" : "getIP", "generate" : "jswrap_ethernet_getIP", "params" : [ ["options","JsVar","An optional `callback(err, ipinfo)` function to be called back with the IP information."] ], "return" : ["JsVar",""] } Get the current IP address, subnet, gateway and mac address. */ JsVar *jswrap_ethernet_getIP(JsVar *wlanObj, JsVar *callback) { NOT_USED(wlanObj); if (networkState != NETWORKSTATE_ONLINE) { jsExceptionHere(JSET_ERROR, "Not connected to the internet"); return 0; } JsNetwork net; if (!networkGetFromVar(&net)) return 0; wiz_NetInfo gWIZNETINFO; ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO); /* If byte 1 is 0 we don't have a valid address */ JsVar *data = jsvNewObject(); networkPutAddressAsString(data, "ip", &gWIZNETINFO.ip[0], 4, 10, '.'); networkPutAddressAsString(data, "subnet", &gWIZNETINFO.sn[0], 4, 10, '.'); networkPutAddressAsString(data, "gateway", &gWIZNETINFO.gw[0], 4, 10, '.'); networkPutAddressAsString(data, "dns", &gWIZNETINFO.dns[0], 4, 10, '.'); networkPutAddressAsString(data, "mac", &gWIZNETINFO.mac[0], 6, 16, ':'); networkFree(&net); // Schedule callback if a function was provided if (jsvIsFunction(callback)) { JsVar *params[2]; params[0] = jsvNewWithFlags(JSV_NULL); params[1] = data; jsiQueueEvents(NULL, callback, params, 2); jsvUnLock(params[0]); } return data; }
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 } } }
// httpParseHeaders(&receiveData, reqVar, true) // server // httpParseHeaders(&receiveData, resVar, false) // client bool httpParseHeaders(JsVar **receiveData, JsVar *objectForData, bool isServer) { // find /r/n/r/n int newlineIdx = 0; int strIdx = 0; int headerEnd = -1; JsvStringIterator it; jsvStringIteratorNew(&it, *receiveData, 0); while (jsvStringIteratorHasChar(&it)) { char ch = jsvStringIteratorGetChar(&it); if (ch == '\r') { if (newlineIdx==0) newlineIdx=1; else if (newlineIdx==2) newlineIdx=3; } else if (ch == '\n') { if (newlineIdx==1) newlineIdx=2; else if (newlineIdx==3) { headerEnd = strIdx+1; break; } } else newlineIdx=0; jsvStringIteratorNext(&it); strIdx++; } jsvStringIteratorFree(&it); // skip if we have no header if (headerEnd<0) return false; // Now parse the header JsVar *vHeaders = jsvNewObject(); if (!vHeaders) return true; jsvUnLock(jsvAddNamedChild(objectForData, vHeaders, "headers")); strIdx = 0; int firstSpace = -1; int secondSpace = -1; int firstEOL = -1; int lineNumber = 0; int lastLineStart = 0; int colonPos = 0; //jsiConsolePrintStringVar(receiveData); jsvStringIteratorNew(&it, *receiveData, 0); while (jsvStringIteratorHasChar(&it)) { char ch = jsvStringIteratorGetChar(&it); if (ch==' ' || ch=='\r') { if (firstSpace<0) firstSpace = strIdx; else if (secondSpace<0) secondSpace = strIdx; } if (ch == ':' && colonPos<0) colonPos = strIdx; if (ch == '\r') { if (firstEOL<0) firstEOL=strIdx; if (lineNumber>0 && colonPos>lastLineStart && lastLineStart<strIdx) { JsVar *hVal = jsvNewFromEmptyString(); if (hVal) jsvAppendStringVar(hVal, *receiveData, (size_t)colonPos+2, (size_t)(strIdx-(colonPos+2))); JsVar *hKey = jsvNewFromEmptyString(); if (hKey) { jsvMakeIntoVariableName(hKey, hVal); jsvAppendStringVar(hKey, *receiveData, (size_t)lastLineStart, (size_t)(colonPos-lastLineStart)); jsvAddName(vHeaders, hKey); jsvUnLock(hKey); } jsvUnLock(hVal); } lineNumber++; colonPos=-1; } if (ch == '\r' || ch == '\n') { lastLineStart = strIdx+1; } jsvStringIteratorNext(&it); strIdx++; } jsvStringIteratorFree(&it); jsvUnLock(vHeaders); // try and pull out methods/etc if (isServer) { jsvObjectSetChildAndUnLock(objectForData, "method", jsvNewFromStringVar(*receiveData, 0, (size_t)firstSpace)); jsvObjectSetChildAndUnLock(objectForData, "url", jsvNewFromStringVar(*receiveData, (size_t)(firstSpace+1), (size_t)(secondSpace-(firstSpace+1)))); } else { jsvObjectSetChildAndUnLock(objectForData, "httpVersion", jsvNewFromStringVar(*receiveData, 5, (size_t)firstSpace-5)); jsvObjectSetChildAndUnLock(objectForData, "statusCode", jsvNewFromStringVar(*receiveData, (size_t)(firstSpace+1), (size_t)(secondSpace-(firstSpace+1)))); jsvObjectSetChildAndUnLock(objectForData, "statusMessage", jsvNewFromStringVar(*receiveData, (size_t)(secondSpace+1), (size_t)(firstEOL-(secondSpace+1)))); } // strip out the header JsVar *afterHeaders = jsvNewFromStringVar(*receiveData, (size_t)headerEnd, JSVAPPENDSTRINGVAR_MAXLENGTH); jsvUnLock(*receiveData); *receiveData = afterHeaders; return true; }
/**@brief Function for the application's SoftDevice event handler. * * @param[in] p_ble_evt SoftDevice event. */ static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_TIMEOUT: // the timeout for sd_ble_gap_adv_start expired - kick it off again jswrap_nrf_bluetooth_startAdvertise(); break; case BLE_GAP_EVT_CONNECTED: m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; bleStatus &= ~BLE_IS_SENDING; // reset state - just in case jsiSetConsoleDevice( EV_BLUETOOTH ); break; case BLE_GAP_EVT_DISCONNECTED: m_conn_handle = BLE_CONN_HANDLE_INVALID; jsiSetConsoleDevice( DEFAULT_CONSOLE_DEVICE ); // restart advertising after disconnection jswrap_nrf_bluetooth_startAdvertise(); break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: // Pairing not supported err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); APP_ERROR_CHECK(err_code); break; case BLE_GATTS_EVT_SYS_ATTR_MISSING: // No system attributes have been stored. err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0); APP_ERROR_CHECK(err_code); break; case BLE_EVT_TX_COMPLETE: // UART Transmit finished - we can try and send more data bleStatus &= ~BLE_IS_SENDING; jswrap_nrf_transmit_string(); break; case BLE_GAP_EVT_ADV_REPORT: { // Advertising data received const ble_gap_evt_adv_report_t *p_adv = &p_ble_evt->evt.gap_evt.params.adv_report; JsVar *evt = jsvNewObject(); if (evt) { jsvObjectSetChildAndUnLock(evt, "rssi", jsvNewFromInteger(p_adv->rssi)); jsvObjectSetChildAndUnLock(evt, "addr", jsvVarPrintf("%02x:%02x:%02x:%02x:%02x:%02x", p_adv->peer_addr.addr[5], p_adv->peer_addr.addr[4], p_adv->peer_addr.addr[3], p_adv->peer_addr.addr[2], p_adv->peer_addr.addr[1], p_adv->peer_addr.addr[0])); JsVar *data = jsvNewStringOfLength(p_adv->dlen); if (data) { jsvSetString(data, p_adv->data, p_adv->dlen); JsVar *ab = jsvNewArrayBufferFromString(data, p_adv->dlen); jsvUnLock(data); jsvObjectSetChildAndUnLock(evt, "data", ab); } jsiQueueObjectCallbacks(execInfo.root, BLE_SCAN_EVENT, &evt, 1); jsvUnLock(evt); } break; } default: // No implementation needed. break; } }
/*JSON{ "type" : "staticmethod", "class" : "url", "name" : "parse", "generate" : "jswrap_url_parse", "params" : [ ["urlStr","JsVar","A URL to be parsed"], ["parseQuery","bool","Whether to parse the query string into an object not (default = false)"] ], "return" : ["JsVar","An object containing options for ```http.request``` or ```http.get```. Contains `method`, `host`, `path`, `pathname`, `search`, `port` and `query`"] } A utility function to split a URL into parts This is useful in web servers for instance when handling a request. For instance `url.parse("/a?b=c&d=e",true)` returns `{"method":"GET","host":"","path":"/a?b=c&d=e","pathname":"/a","search":"?b=c&d=e","port":80,"query":{"b":"c","d":"e"}}` */ JsVar *jswrap_url_parse(JsVar *url, bool parseQuery) { if (!jsvIsString(url)) return 0; JsVar *obj = jsvNewObject(); if (!obj) return 0; // out of memory // scan string to try and pick stuff out JsvStringIterator it; jsvStringIteratorNew(&it, url, 0); int slashes = 0; int colons = 0; int addrStart = -1; int portStart = -1; int pathStart = -1; int searchStart = -1; int charIdx = 0; int portNumber = 0; while (jsvStringIteratorHasChar(&it)) { char ch = jsvStringIteratorGetChar(&it); if (ch == '/') { slashes++; if (pathStart<0) pathStart = charIdx; if (colons==1 && slashes==2 && addrStart<0) { addrStart = charIdx; pathStart = -1; searchStart = -1; } } if (ch == ':') { colons++; if (addrStart>=0 && pathStart<0) portStart = charIdx; } if (portStart>=0 && charIdx>portStart && pathStart<0 && ch >= '0' && ch <= '9') { portNumber = portNumber*10 + (ch-'0'); } if (ch == '?' && pathStart>=0) { searchStart = charIdx; } jsvStringIteratorNext(&it); charIdx++; } jsvStringIteratorFree(&it); // try and sort stuff out if (pathStart<0) pathStart = charIdx; if (pathStart<0) pathStart = charIdx; int addrEnd = (portStart>=0) ? portStart : pathStart; // pull out details if (addrStart>0) jsvObjectSetChildAndUnLock(obj, "protocol", jsvNewFromStringVar(url, 0, (size_t)addrStart-1)); jsvObjectSetChildAndUnLock(obj, "method", jsvNewFromString("GET")); jsvObjectSetChildAndUnLock(obj, "host", jsvNewFromStringVar(url, (size_t)(addrStart+1), (size_t)(addrEnd-(addrStart+1)))); JsVar *v; v = jsvNewFromStringVar(url, (size_t)pathStart, JSVAPPENDSTRINGVAR_MAXLENGTH); if (jsvGetStringLength(v)==0) jsvAppendString(v, "/"); jsvObjectSetChildAndUnLock(obj, "path", v); v = jsvNewFromStringVar(url, (size_t)pathStart, (size_t)((searchStart>=0)?(searchStart-pathStart):JSVAPPENDSTRINGVAR_MAXLENGTH)); if (jsvGetStringLength(v)==0) jsvAppendString(v, "/"); jsvObjectSetChildAndUnLock(obj, "pathname", v); jsvObjectSetChildAndUnLock(obj, "search", (searchStart>=0)?jsvNewFromStringVar(url, (size_t)searchStart, JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull()); jsvObjectSetChildAndUnLock(obj, "port", (portNumber<=0 || portNumber>65535) ? jsvNewWithFlags(JSV_NULL) : jsvNewFromInteger(portNumber)); JsVar *query = (searchStart>=0)?jsvNewFromStringVar(url, (size_t)(searchStart+1), JSVAPPENDSTRINGVAR_MAXLENGTH):jsvNewNull(); if (parseQuery && !jsvIsNull(query)) { JsVar *queryStr = query; jsvStringIteratorNew(&it, query, 0); query = jsvNewObject(); JsVar *key = jsvNewFromEmptyString(); JsVar *val = jsvNewFromEmptyString(); bool hadEquals = false; while (jsvStringIteratorHasChar(&it)) { char ch = jsvStringIteratorGetChar(&it); if (ch=='&') { if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) { key = jsvAsArrayIndexAndUnLock(key); // make sure "0" gets made into 0 jsvMakeIntoVariableName(key, val); jsvAddName(query, key); jsvUnLock2(key, val); key = jsvNewFromEmptyString(); val = jsvNewFromEmptyString(); hadEquals = false; } } else if (!hadEquals && ch=='=') { hadEquals = true; } else { // decode percent escape chars if (ch=='%') { jsvStringIteratorNext(&it); ch = jsvStringIteratorGetChar(&it); jsvStringIteratorNext(&it); ch = (char)((chtod(ch)<<4) | chtod(jsvStringIteratorGetChar(&it))); } if (hadEquals) jsvAppendCharacter(val, ch); else jsvAppendCharacter(key, ch); } jsvStringIteratorNext(&it); charIdx++; } jsvStringIteratorFree(&it); jsvUnLock(queryStr); if (jsvGetStringLength(key)>0 || jsvGetStringLength(val)>0) { key = jsvAsArrayIndexAndUnLock(key); // make sure "0" gets made into 0 jsvMakeIntoVariableName(key, val); jsvAddName(query, key); } jsvUnLock2(key, val); } jsvObjectSetChildAndUnLock(obj, "query", query); return obj; }