/** Set up a UART, if pins are -1 they will be guessed */ void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf) { if (device != EV_SERIAL1) return; int baud = getNRFBaud(inf->baudRate); if (baud==0) return jsError("Invalid baud rate %d", inf->baudRate); if (!jshIsPinValid(inf->pinRX) || !jshIsPinValid(inf->pinTX)) return jsError("Invalid RX or TX pins"); uint32_t err_code; const app_uart_comm_params_t comm_params = { pinInfo[inf->pinRX].pin, pinInfo[inf->pinTX].pin, (uint8_t)UART_PIN_DISCONNECTED, (uint8_t)UART_PIN_DISCONNECTED, APP_UART_FLOW_CONTROL_DISABLED, inf->parity!=0, // TODO: ODD or EVEN parity? baud }; APP_UART_INIT(&comm_params, uart0_event_handle, APP_IRQ_PRIORITY_HIGH, err_code); APP_ERROR_CHECK(err_code); }
IOEventFlags jshPinWatch(Pin pin, bool shouldWatch) { if (jshIsPinValid(pin)) { IOEventFlags exti = getNewEVEXTI(); if (shouldWatch) { if (exti) { gpioEventFlags[pin] = exti; jshPinSetState(pin, JSHPINSTATE_GPIO_IN); #ifdef SYSFS_GPIO_DIR gpioShouldWatch[pin] = true; gpioLastState[pin] = jshPinGetValue(pin); #endif #ifdef USE_WIRINGPI wiringPiISR(pin, INT_EDGE_BOTH, irqEXTIs[exti-EV_EXTI0]); #endif } else jsError("You can only have a maximum of 16 watches!"); } if (!shouldWatch || !exti) { gpioEventFlags[pin] = 0; #ifdef SYSFS_GPIO_DIR gpioShouldWatch[pin] = false; #endif #ifdef USE_WIRINGPI wiringPiISR(pin, INT_EDGE_BOTH, irqEXTIDoNothing); #endif } return shouldWatch ? exti : EV_NONE; } else jsError("Invalid pin!"); return EV_NONE; }
/*JSON{ "type":"method", "class": "Array", "name" : "reduce", "description" : "Execute `previousValue=initialValue` and then `previousValue = callback(previousValue, currentValue, index, array)` for each element in the array, and finally return previousValue.", "generate" : "jswrap_array_reduce", "params" : [ [ "callback", "JsVar", "Function used to reduce the array"] , [ "initialValue", "JsVar", "if specified, the initial value to pass to the function"] ], "return" : ["JsVar", "The value returned by the last function called"] }*/ JsVar *jswrap_array_reduce(JsVar *parent, JsVar *funcVar, JsVar *initialValue) { const char *name = "reduce"; if (!jsvIsIterable(parent)) { jsError("Array.%s can only be called on something iterable", name); return 0; } if (!jsvIsFunction(funcVar)) { jsError("Array.%s's first argument should be a function", name); return 0; } JsVar *previousValue = initialValue ? jsvLockAgain(initialValue) : 0; JsvIterator it; jsvIteratorNew(&it, parent); while (jsvIteratorHasElement(&it)) { JsVar *index = jsvIteratorGetKey(&it); if (jsvIsInt(index)) { JsVarInt idxValue = jsvGetInteger(index); JsVar *args[4]; args[0] = previousValue; args[1] = jsvIteratorGetValue(&it); args[2] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index args[3] = parent; previousValue = jspeFunctionCall(funcVar, 0, 0, false, 4, args); jsvUnLock(args[0]); jsvUnLock(args[1]); jsvUnLock(args[2]); } jsvUnLock(index); jsvIteratorNext(&it); } jsvIteratorFree(&it); return previousValue; }
/*JSON{ "type" : "staticmethod", "class" : "crypto", "name" : "PBKDF2", "generate" : "jswrap_crypto_PBKDF2", "params" : [ ["passphrase","JsVar","Passphrase"], ["salt","JsVar","Salt for turning passphrase into a key"], ["options","JsVar","Object of Options, `{ keySize: 8 (in 32 bit words), iterations: 10, hasher: 'SHA1'/'SHA224'/'SHA256'/'SHA384'/'SHA512' }`"] ], "return" : ["JsVar","Returns an ArrayBuffer"], "return_object" : "ArrayBuffer", "ifdef" : "USE_TLS" } Password-Based Key Derivation Function 2 algorithm, using SHA512 */ JsVar *jswrap_crypto_PBKDF2(JsVar *passphrase, JsVar *salt, JsVar *options) { int iterations = 1; int keySize = 128/32; mbedtls_md_type_t hasher = MBEDTLS_MD_SHA1; if (jsvIsObject(options)) { keySize = jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "keySize", 0)); if (keySize<=0) keySize=128/32; iterations = jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "iterations", 0)); if (iterations<1) iterations = 1; JsVar *hashVar = jsvObjectGetChild(options, "hasher", 0); if (!jsvIsUndefined(hashVar)) hasher = jswrap_crypto_getHasher(hashVar); jsvUnLock(hashVar); } else if (!jsvIsUndefined(options)) jsError("Options should be an object or undefined, got %t", options); if (hasher == MBEDTLS_MD_NONE) return 0; // already shown an error JSV_GET_AS_CHAR_ARRAY(passPtr, passLen, passphrase); if (!passPtr) return 0; JSV_GET_AS_CHAR_ARRAY(saltPtr, saltLen, salt); if (!saltPtr) return 0; int err; mbedtls_md_context_t ctx; mbedtls_md_init( &ctx ); err = mbedtls_md_setup( &ctx, mbedtls_md_info_from_type( hasher ), 1 ); assert(err==0); char *keyPtr = 0; JsVar *keyArr = jsvNewArrayBufferWithPtr((unsigned)keySize*4, &keyPtr); if (!keyPtr) { jsError("Not enough memory for result"); return 0; } err = mbedtls_pkcs5_pbkdf2_hmac( &ctx, (unsigned char*)passPtr, passLen, (unsigned char*)saltPtr, saltLen, (unsigned)iterations, (unsigned)keySize*4, (unsigned char*)keyPtr ); mbedtls_md_free( &ctx ); if (!err) { return keyArr; } else { jswrap_crypto_error(err); jsvUnLock(keyArr); return 0; } }
void jswrap_crypto_error(int err) { const char *e = 0; switch(err) { case MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE: e="Feature unavailable"; break; case MBEDTLS_ERR_MD_BAD_INPUT_DATA: e="Bad Input Data"; break; case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH: e="Invalid input length"; break; } if (e) jsError(e); else jsError("Unknown error: -0x%x", -err); }
/*JSON{ "type":"function", "name" : "edit", "description" : ["Fill the console with the contents of the given function, so you can edit it.", "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."], "generate" : "jswrap_interface_edit", "params" : [ [ "funcName", "JsVar", "The name of the function to edit (either a string or just the unquoted name)"] ] }*/ void jswrap_interface_edit(JsVar *funcName) { JsVar *func = 0; if (jsvIsString(funcName)) { funcName = jsvLockAgain(funcName); func = jsvSkipNameAndUnLock(jsvFindChildFromVar(execInfo.root, funcName, 0)); } else { func = funcName; funcName = jsvGetPathTo(execInfo.root, func, 2); } if (jsvIsString(funcName)) { if (jsvIsFunction(func)) { JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false); JsVar *inRoot = jsvGetArrayIndexOf(execInfo.root, func, true); bool normalDecl = scopeVar==0 && inRoot!=0; jsvUnLock(inRoot); jsvUnLock(scopeVar); JsVar *newLine = jsvNewFromEmptyString(); if (newLine) { // could be out of memory /* normalDecl: * * function foo() { ... } * * NOT normalDecl: * * foo.replaceWith(function() { ... }); * */ JsVar *funcData = jsvAsString(func, false); if (normalDecl) { jsvAppendString(newLine, "function "); jsvAppendStringVarComplete(newLine, funcName); jsvAppendStringVar(newLine, funcData, 9, JSVAPPENDSTRINGVAR_MAXLENGTH); } else { jsvAppendStringVarComplete(newLine, funcName); jsvAppendString(newLine, ".replaceWith("); jsvAppendStringVarComplete(newLine, funcData); jsvAppendString(newLine, ");"); } jsvUnLock(funcData); jsiReplaceInputLine(newLine); jsvUnLock(newLine); } } else { jsError("Edit should be called with the name of a function"); } } else { jsError("Edit should be called with edit(funcName) or edit('funcName')"); } jsvUnLock(func); jsvUnLock(funcName); }
// Connect this connection/socket void clientRequestConnect(JsNetwork *net, JsVar *httpClientReqVar) { // Have we already connected? If so, don't go further if (jsvGetIntegerAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SOCKET, 0))>0) return; SocketType socketType = socketGetType(httpClientReqVar); JsVar *options = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_OPTIONS_VAR, false); unsigned short port = (unsigned short)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "port", 0)); char hostName[128]; JsVar *hostNameVar = jsvObjectGetChild(options, "host", 0); if (jsvIsUndefined(hostNameVar)) strncpy(hostName, "localhost", sizeof(hostName)); else jsvGetString(hostNameVar, hostName, sizeof(hostName)); jsvUnLock(hostNameVar); uint32_t host_addr = 0; networkGetHostByName(net, hostName, &host_addr); if(!host_addr) { jsError("Unable to locate host\n"); // As this is already in the list of connections, an error will be thrown on idle anyway jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_CLOSENOW, jsvNewFromBool(true)); jsvUnLock(options); netCheckError(net); return; } NetCreateFlags flags = NCF_NORMAL; #ifdef USE_TLS if (socketType & ST_TLS) { flags |= NCF_TLS; if (port==0) port = 443; } #endif if (port==0) port = 80; int sckt = netCreateSocket(net, host_addr, port, flags, options); if (sckt<0) { jsError("Unable to create socket\n"); // As this is already in the list of connections, an error will be thrown on idle anyway jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_CLOSENOW, jsvNewFromBool(true)); } else { jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_SOCKET, jsvNewFromInteger(sckt+1)); } jsvUnLock(options); netCheckError(net); }
void lcdInit_SDL(JsGraphics *gfx) { if (SDL_Init(SDL_INIT_VIDEO) < 0 ) { jsError("SDL_Init failed\n"); exit(1); } if (!(screen = SDL_SetVideoMode(gfx->data.width, gfx->data.height, gfx->data.bpp, SDL_SWSURFACE))) { jsError("SDL_SetVideoMode failed\n"); SDL_Quit(); exit(1); } }
/*JSON{ "type":"method", "class": "ArrayBufferView", "name" : "map", "description" : ["Return an array which is made from the following: ```A.map(function) = [function(A[0]), function(A[1]), ...]```", "**Note:** This returns an ArrayBuffer of the same type it was called on. To get an Array, use `Array.prototype.map`" ], "generate" : "jswrap_arraybufferview_map", "params" : [ [ "function", "JsVar", "Function used to map one item to another"] , [ "thisArg", "JsVar", "if specified, the function is called with 'this' set to thisArg (optional)"] ], "return" : ["JsVar", "An array containing the results"] }*/ JsVar *jswrap_arraybufferview_map(JsVar *parent, JsVar *funcVar, JsVar *thisVar) { if (!jsvIsArrayBuffer(parent)) { jsError("ArrayBufferView.map can only be called on an ArrayBufferView"); return 0; } if (!jsvIsFunction(funcVar)) { jsError("ArrayBufferView.map's first argument should be a function"); return 0; } if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) { jsError("ArrayBufferView.map's second argument should be undefined, or an object"); return 0; } // create ArrayBuffer result JsVarDataArrayBufferViewType arrayBufferType = parent->varData.arraybuffer.type; JsVar *arrayBufferLength = jsvNewFromInteger((JsVarInt)jsvGetArrayBufferLength(parent)); JsVar *array = jswrap_typedarray_constructor(arrayBufferType, arrayBufferLength, 0, 0); jsvUnLock(arrayBufferLength); if (!array) return 0; // now iterate JsvIterator it; // TODO: if we really are limited to ArrayBuffers, this could be an ArrayBufferIterator. jsvIteratorNew(&it, parent); JsvArrayBufferIterator itdst; jsvArrayBufferIteratorNew(&itdst, array, 0); while (jsvIteratorHasElement(&it)) { JsVar *index = jsvIteratorGetKey(&it); if (jsvIsInt(index)) { JsVarInt idxValue = jsvGetInteger(index); JsVar *args[3], *mapped; args[0] = jsvIteratorGetValue(&it); args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index args[2] = parent; mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args); jsvUnLock(args[0]); jsvUnLock(args[1]); if (mapped) { jsvArrayBufferIteratorSetValue(&itdst, mapped); jsvUnLock(mapped); } } jsvUnLock(index); jsvIteratorNext(&it); jsvArrayBufferIteratorNext(&itdst); } jsvIteratorFree(&it); jsvArrayBufferIteratorFree(&itdst); return array; }
JsVar *_jswrap_array_map_or_forEach(JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool isMap) { const char *name = isMap ? "map":"forEach"; if (!jsvIsIterable(parent)) { jsError("Array.%s can only be called on something iterable", name); return 0; } if (!jsvIsFunction(funcVar)) { jsError("Array.%s's first argument should be a function", name); return 0; } if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) { jsError("Array.%s's second argument should be undefined, or an object", name); return 0; } JsVar *array = 0; if (isMap) array = jsvNewWithFlags(JSV_ARRAY); if (array || !isMap) { JsvIterator it; jsvIteratorNew(&it, parent); while (jsvIteratorHasElement(&it)) { JsVar *index = jsvIteratorGetKey(&it); if (jsvIsInt(index)) { JsVarInt idxValue = jsvGetInteger(index); JsVar *args[3], *mapped; args[0] = jsvIteratorGetValue(&it); args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index args[2] = parent; mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args); jsvUnLock(args[0]); jsvUnLock(args[1]); if (mapped) { if (isMap) { JsVar *name = jsvNewFromInteger(idxValue); if (name) { // out of memory? jsvMakeIntoVariableName(name, mapped); jsvAddName(array, name); jsvUnLock(name); } } jsvUnLock(mapped); } } jsvUnLock(index); jsvIteratorNext(&it); } jsvIteratorFree(&it); } return array; }
void jshSPISetup(IOEventFlags device, JshSPIInfo *inf) { assert(DEVICE_IS_SPI(device)); if (ioDevices[device]) close(ioDevices[device]); ioDevices[device] = 0; char path[256]; if (jshGetDevicePath(device, path, sizeof(path))) { ioDevices[device] = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (!ioDevices[device]) { jsError("Open of path %s failed", path); } else { } } else { jsError("No path defined for device"); } }
/*JSON{ "type":"constructor", "class": "ArrayBuffer", "name": "ArrayBuffer", "description" : "Create an Array Buffer object", "generate" : "jswrap_arraybuffer_constructor", "params" : [ [ "byteLength", "int", "The length in Bytes" ] ], "return" : [ "JsVar", "An ArrayBuffer object" ] }*/ JsVar *jswrap_arraybuffer_constructor(JsVarInt byteLength) { if (byteLength <= 0 || byteLength>65535) { jsError("Invalid length for ArrayBuffer\n"); return 0; } if (byteLength > JSV_ARRAYBUFFER_MAX_LENGTH) { jsError("ArrayBuffer too long\n"); return 0; } JsVar *arrData = jsvNewStringOfLength((unsigned int)byteLength); if (!arrData) return 0; JsVar *v = jsvNewArrayBufferFromString(arrData, (int)byteLength); jsvUnLock(arrData); return v; }
bool jsfsInit() { #ifndef LINUX if (!fat_initialised) { #ifdef SD_CARD_ANYWHERE if (!isSdSPISetup()) { #ifdef SD_SPI const char *deviceStr = jshGetDeviceString(SD_SPI); JsVar *spi = jsvSkipNameAndUnLock(jspGetNamedVariable(deviceStr)); JshSPIInfo inf; jshSPIInitInfo(&inf); inf.pinMISO = SD_DO_PIN; inf.pinMOSI = SD_DI_PIN; inf.pinSCK = SD_CLK_PIN; jshSPISetup(SD_SPI, &inf); sdSPISetup(spi, SD_CS_PIN); jsvUnLock(spi); #else jsError("SD card must be setup with E.connectSDCard first"); return false; #endif } #endif FRESULT res; if ((res = f_mount(&jsfsFAT, "", 1/*immediate*/)) != FR_OK) { jsfsReportError("Unable to mount SD card", res); return false; } fat_initialised = true; } #endif return true; }
/*JSON{ "type":"method", "class" : "Ethernet", "name" : "setIP", "generate" : "jswrap_ethernet_setIP", "description" : "Set the current IP address for get an IP from DHCP (if no options object is specified)", "params" : [ [ "options", "JsVar", "Object containing IP address options `{ ip : '1,2,3,4', subnet, gateway, dns }`, or do not supply an object in otder to force DHCP."] ], "return" : ["bool", "True on success"] }*/ bool jswrap_ethernet_setIP(JsVar *wlanObj, JsVar *options) { NOT_USED(wlanObj); if (networkState != NETWORKSTATE_ONLINE) { jsError("Not connected to the internet"); return false; } bool success = false; wiz_NetInfo gWIZNETINFO; ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO); if (jsvIsObject(options)) { _eth_getIP_set_address(options, "ip", &gWIZNETINFO.ip[0]); _eth_getIP_set_address(options, "subnet", &gWIZNETINFO.sn[0]); _eth_getIP_set_address(options, "gateway", &gWIZNETINFO.gw[0]); _eth_getIP_set_address(options, "dns", &gWIZNETINFO.dns[0]); gWIZNETINFO.dhcp = NETINFO_STATIC; success = true; } else { // DHCP uint8_t DHCPisSuccess = getIP_DHCPS(net_wiznet_getFreeSocket(), &gWIZNETINFO); if (DHCPisSuccess == 1) { // info in lease_time.lVal success = true; } else { jsWarn("DHCP failed"); success = false; } } ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO); return success; }
/*JSON{ "type" : "method", "class" : "Ethernet", "name" : "getIP", "generate" : "jswrap_ethernet_getIP", "return" : ["JsVar",""] } Get the current IP address, subnet, gateway and mac address. */ JsVar *jswrap_ethernet_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; wiz_NetInfo gWIZNETINFO; ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO); /* If byte 1 is 0 we don't have a valid address */ JsVar *data = jsvNewWithFlags(JSV_OBJECT); 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); return data; }
/*JSON{ "type":"method", "class": "ArrayBufferView", "name": "set", "description" : "Copy the contents of `array` into this one, mapping `this[x+offset]=array[x];`", "generate" : "jswrap_arraybufferview_set", "params" : [ [ "arr", "JsVar", "Floating point index to access" ], ["offset","int32","The offset in this array at which to write the values (optional)"] ] }*/ void jswrap_arraybufferview_set(JsVar *parent, JsVar *arr, int offset) { if (!(jsvIsString(arr) || jsvIsArray(arr) || jsvIsArrayBuffer(arr))) { jsError("Expecting first argument to be an array, not %t", arr); return; } JsvIterator itsrc; jsvIteratorNew(&itsrc, arr); JsvArrayBufferIterator itdst; jsvArrayBufferIteratorNew(&itdst, parent, (size_t)offset); bool useInts = JSV_ARRAYBUFFER_IS_FLOAT(itdst.type) || jsvIsString(arr); while (jsvIteratorHasElement(&itsrc) && jsvArrayBufferIteratorHasElement(&itdst)) { if (useInts) { jsvArrayBufferIteratorSetIntegerValue(&itdst, jsvIteratorGetIntegerValue(&itsrc)); } else { JsVar *value = jsvIteratorGetValue(&itsrc); jsvArrayBufferIteratorSetValue(&itdst, value); jsvUnLock(value); } jsvArrayBufferIteratorNext(&itdst); jsvIteratorNext(&itsrc); } jsvArrayBufferIteratorFree(&itdst); jsvIteratorFree(&itsrc); }
/// if host=0, creates a server otherwise creates a client (and automatically connects). Returns >=0 on success int net_cc3000_createsocket(JsNetwork *net, unsigned long host, unsigned short port) { int sckt = -1; if (host!=0) { // ------------------------------------------------- host (=client) sockaddr sin; sin.sa_family = AF_INET; sin.sa_data[0] = (unsigned char)((port & 0xFF00) >> 8); sin.sa_data[1] = (unsigned char)(port & 0x00FF); sckt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sckt<0) return sckt; // error int param; param = SOCK_ON; setsockopt(sckt, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, ¶m, sizeof(param)); // enable nonblock param = 5; // ms setsockopt(sckt, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, ¶m, sizeof(param)); // set a timeout sin.sa_data[5] = (unsigned char)((host) & 0xFF); // First octet of destination IP sin.sa_data[4] = (unsigned char)((host>>8) & 0xFF); // Second Octet of destination IP sin.sa_data[3] = (unsigned char)((host>>16) & 0xFF); // Third Octet of destination IP sin.sa_data[2] = (unsigned char)((host>>24) & 0xFF); // Fourth Octet of destination IP int res = connect(sckt,(struct sockaddr *)&sin, sizeof(sockaddr_in) ); if (res == SOCKET_ERROR) { int err = errno; if (err != EINPROGRESS && err != EWOULDBLOCK) { jsError("Connect failed (err %d)\n", err ); } } } else { // ------------------------------------------------- no host (=server)
bool socketSendData(JsNetwork *net, JsVar *connection, int sckt, JsVar **sendData) { char buf[64]; int a=1; if (!jsvIsEmptyString(*sendData)) { size_t bufLen = httpStringGet(*sendData, buf, sizeof(buf)); a = net->send(net, sckt, buf, bufLen); // Now cut what we managed to send off the beginning of sendData if (a>0) { JsVar *newSendData = 0; if (a < (int)jsvGetStringLength(*sendData)) { // we didn't send all of it... cut out what we did send newSendData = jsvNewFromStringVar(*sendData, (size_t)a, JSVAPPENDSTRINGVAR_MAXLENGTH); } else { // we sent all of it! Issue a drain event jsiQueueObjectCallbacks(connection, "#ondrain", &connection, 1); } jsvUnLock(*sendData); *sendData = newSendData; } } if (a<0) { // could just be busy which is ok jsError("Socket error %d while sending", a); return false; } return true; }
/// if host=0, creates a server otherwise creates a client (and automatically connects). Returns >=0 on success int net_wiznet_createsocket(JsNetwork *net, unsigned long host, unsigned short port) { NOT_USED(net); int sckt = -1; if (host!=0) { // ------------------------------------------------- host (=client) //mgg1010 - added random source port - seems to solve problem of repeated GET failing sckt = socket(net_wiznet_getFreeSocket(), Sn_MR_TCP, (uint16_t)((rand() & 32767) + 2000), 0); // we set nonblocking later if (sckt<0) return sckt; // error int res = connect((uint8_t)sckt,(uint8_t*)&host, port); // now we set nonblocking - so that connect waited for the connection uint8_t ctl = SOCK_IO_NONBLOCK; ctlsocket((uint8_t)sckt, CS_SET_IOMODE, &ctl); if (res == SOCKET_ERROR) { jsError("Connect failed (err %d)\n", res ); } } else { // ------------------------------------------------- no host (=server) sckt = socket(net_wiznet_getFreeSocket(), Sn_MR_TCP, port, SF_IO_NONBLOCK); listen((uint8_t)sckt); } wiznetSocketPorts[sckt&7] = port; //jsiConsolePrintf("Created socket %d\n", sckt); return sckt; }
/*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 = jsvNewWithFlags(JSV_OBJECT); 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; }
JsVar *jswrap_arguments() { JsVar *scope = 0; if (execInfo.scopeCount>0) scope = jsvLock(execInfo.scopes[execInfo.scopeCount-1]); if (!jsvIsFunction(scope)) { jsvUnLock(scope); jsError("Can only use 'arguments' variable inside a function"); return 0; } JsVar *args = jsvNewWithFlags(JSV_ARRAY); if (!args) return 0; // out of memory JsvObjectIterator it; jsvObjectIteratorNew(&it, scope); while (jsvObjectIteratorHasElement(&it)) { JsVar *idx = jsvObjectIteratorGetKey(&it); if (jsvIsFunctionParameter(idx)) { JsVar *val = jsvSkipOneName(idx); jsvArrayPushAndUnLock(args, val); } jsvUnLock(idx); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(scope); return args; }
/*JSON{ "type":"method", "class" : "WLAN", "name" : "setIP", "generate" : "jswrap_wlan_setIP", "description" : ["Set the current IP address for get an IP from DHCP (if no options object is specified).", "**Note:** Changes are written to non-volatile memory, but will only take effect after calling `wlan.reconnect()`" ], "params" : [ [ "options", "JsVar", "Object containing IP address options `{ ip : '1,2,3,4', subnet, gateway, dns }`, or do not supply an object in otder to force DHCP."] ], "return" : ["bool", "True on success"] }*/ bool jswrap_wlan_setIP(JsVar *wlanObj, JsVar *options) { NOT_USED(wlanObj); if (networkState != NETWORKSTATE_ONLINE) { jsError("Not connected to the internet"); return false; } tNetappIpconfigRetArgs ipconfig; netapp_ipconfig(&ipconfig); if (jsvIsObject(options)) { _wlan_getIP_set_address(options, "ip", &ipconfig.aucIP[0]); _wlan_getIP_set_address(options, "subnet", &ipconfig.aucSubnetMask[0]); _wlan_getIP_set_address(options, "gateway", &ipconfig.aucDefaultGateway[0]); _wlan_getIP_set_address(options, "dns", &ipconfig.aucDNSServer[0]); } else { // DHCP - just set all values to 0 *((unsigned long*)&ipconfig.aucIP[0]) = 0; *((unsigned long*)&ipconfig.aucSubnetMask) = 0; *((unsigned long*)&ipconfig.aucDefaultGateway) = 0; } return netapp_dhcp( (unsigned long *)&ipconfig.aucIP[0], (unsigned long *)&ipconfig.aucSubnetMask[0], (unsigned long *)&ipconfig.aucDefaultGateway[0], (unsigned long *)&ipconfig.aucDNSServer[0]) == 0; }
/*JSON{ "type" : "function", "name" : "show", "generate" : "jswrap_microbit_show", "params" : [ ["image","JsVar","The image to show"] ] } Show an image on the in-built 5x5 LED screen. Image can be: * A number where each bit represents a pixel (so 25 bits) */ void jswrap_microbit_show(JsVar *image) { if (!jsvIsInt(image)) { jsError("Expecting a number, got %t\n", image); return; } uint32_t newState = jsvGetInteger(image); if ((newState!=0) && (microbitLEDState==0)) { // we want to display something but we don't have an interval jstExecuteFn(jswrap_microbit_display_callback, jshGetTimeFromMilliseconds(5)); // and also set pins to outputs nrf_gpio_cfg_output(MB_LED_COL1); nrf_gpio_cfg_output(MB_LED_COL2); nrf_gpio_cfg_output(MB_LED_COL3); nrf_gpio_cfg_output(MB_LED_COL4); nrf_gpio_cfg_output(MB_LED_COL5); nrf_gpio_cfg_output(MB_LED_COL6); nrf_gpio_cfg_output(MB_LED_COL7); nrf_gpio_cfg_output(MB_LED_COL8); nrf_gpio_cfg_output(MB_LED_COL9); nrf_gpio_cfg_output(MB_LED_ROW1); nrf_gpio_cfg_output(MB_LED_ROW2); nrf_gpio_cfg_output(MB_LED_ROW3); } else if ((newState==0) && (microbitLEDState!=0)) { jswrap_microbit_stopDisplay(); } microbitLEDState = newState; }
/** Push data into a stream. To be used by Espruino (not a user). * This either calls the on('data') handler if it exists, or it * puts the data in a buffer. This MAY CLAIM the string that is * passed in. * * This will return true on success, or false if the buffer is * full. Setting force=true will attempt to fill the buffer as * full as possible, and will raise an error flag if data is lost. */ bool jswrap_stream_pushData(JsVar *parent, JsVar *dataString, bool force) { assert(jsvIsObject(parent)); assert(jsvIsString(dataString)); bool ok = true; JsVar *callback = jsvFindChildFromString(parent, STREAM_CALLBACK_NAME, false); if (callback) { if (!jsiExecuteEventCallback(parent, callback, dataString, 0)) { jsError("Error processing Serial data handler - removing it."); jsErrorFlags |= JSERR_CALLBACK; jsvRemoveNamedChild(parent, STREAM_CALLBACK_NAME); } jsvUnLock(callback); } else { // No callback - try and add buffer JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0); if (!jsvIsString(buf)) { // no buffer, just set this one up jsvObjectSetChild(parent, STREAM_BUFFER_NAME, dataString); } else { // append (if there is room!) size_t bufLen = jsvGetStringLength(buf); size_t dataLen = jsvGetStringLength(dataString); if (bufLen + dataLen > STREAM_MAX_BUFFER_SIZE) { if (force) jsErrorFlags |= JSERR_BUFFER_FULL; // jsWarn("String buffer overflowed maximum size (%d)", STREAM_MAX_BUFFER_SIZE); ok = false; } if ((ok || force) && (bufLen < STREAM_MAX_BUFFER_SIZE)) jsvAppendStringVar(buf, dataString, 0, STREAM_MAX_BUFFER_SIZE-bufLen); jsvUnLock(buf); } } return ok; }
/** * Append new data to the end of the existing memory buffer. */ static uint8 *memoryBuffer_append( struct memoryBuffer *pMemoryBuffer, //!< uint8 *pNewData, //!< size_t length //!< ) { assert(pMemoryBuffer != NULL); if (length == 0) { return pMemoryBuffer->buf; } assert(pNewData != NULL); // Handle the memory buffer being empty. if (pMemoryBuffer->length == 0) { pMemoryBuffer->buf = (uint8 *)os_malloc(length); if (pMemoryBuffer->buf == NULL) { // Out of memory jsError("malloc failed at memoryBuffer_append trying to allocate %d", length); } else { memcpy(pMemoryBuffer->buf, pNewData, length); pMemoryBuffer->length = length; } } else { // The memory buffer was not empty, so we append data. int newSize = pMemoryBuffer->length + length; uint8 *resizedStorage = (uint8 *)os_realloc(pMemoryBuffer->buf, newSize); if (resizedStorage != NULL) { pMemoryBuffer->buf = resizedStorage; memcpy(pMemoryBuffer->buf + length, pNewData, length); pMemoryBuffer->length = newSize; } } return pMemoryBuffer->buf; }
void jshPinPulse(Pin pin, bool value, JsVarFloat time) { if (jshIsPinValid(pin)) { jshPinSetState(pin, JSHPINSTATE_GPIO_OUT); jshPinSetValue(pin, value); usleep(time*1000000); jshPinSetValue(pin, !value); } else jsError("Invalid pin!"); }
/*JSON{ "type" : "staticmethod", "class" : "net", "name" : "connect", "generate_full" : "jswrap_net_connect(options, callback, ST_NORMAL)", "params" : [ ["options","JsVar","An object containing host,port fields"], ["callback","JsVar","A function(res) that will be called when a connection is made. You can then call `res.on('data', function(data) { ... })` and `res.on('close', function() { ... })` to deal with the response."] ], "return" : ["JsVar","Returns a new net.Socket object"], "return_object" : "Socket" } Create a socket connection */ JsVar *jswrap_net_connect(JsVar *options, JsVar *callback, SocketType socketType) { bool unlockOptions = false; if (jsvIsString(options)) { options = jswrap_url_parse(options, false); unlockOptions = true; } if (!jsvIsObject(options)) { jsError("Expecting Options to be an Object but it was %t", options); return 0; } #ifdef USE_TLS if ((socketType&ST_TYPE_MASK) == ST_HTTP) { JsVar *protocol = jsvObjectGetChild(options, "protocol", 0); if (protocol && jsvIsStringEqual(protocol, "https:")) { socketType |= ST_TLS; } jsvUnLock(protocol); } #endif // Make sure we have a function as callback, or nothing (which is OK too) JsVar *skippedCallback = jsvSkipName(callback); if (!jsvIsUndefined(skippedCallback)) { if (!jsvIsFunction(skippedCallback)) { jsError("Expecting Callback Function but got %t", skippedCallback); jsvUnLock(skippedCallback); return 0; } jsvUnLock(skippedCallback); } else { callback = NULL; } JsVar *rq = clientRequestNew(socketType, options, callback); if (unlockOptions) jsvUnLock(options); if ((socketType&ST_TYPE_MASK) != ST_HTTP) { JsNetwork net; if (networkGetFromVarIfOnline(&net)) { clientRequestConnect(&net, rq); } networkFree(&net); } return rq; }
// Connect this connection/socket void clientRequestConnect(JsNetwork *net, JsVar *httpClientReqVar) { SocketType socketType = socketGetType(httpClientReqVar); clientRequestWrite(httpClientReqVar, 0); // force sendData to be made JsVar *options = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_OPTIONS_VAR, false); unsigned short port = (unsigned short)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "port", 0)); if (port==0) port=80; char hostName[128]; JsVar *hostNameVar = jsvObjectGetChild(options, "host", 0); if (jsvIsUndefined(hostNameVar)) strncpy(hostName, "localhost", sizeof(hostName)); else jsvGetString(hostNameVar, hostName, sizeof(hostName)); jsvUnLock(hostNameVar); uint32_t host_addr = 0; networkGetHostByName(net, hostName, &host_addr); if(!host_addr) { jsError("Unable to locate host"); jsvUnLock(jsvObjectSetChild(httpClientReqVar, HTTP_NAME_CLOSENOW, jsvNewFromBool(true))); jsvUnLock(options); net->checkError(net); return; } int sckt = net->createsocket(net, host_addr, port); if (sckt<0) { jsError("Unable to create socket\n"); jsvUnLock(jsvObjectSetChild(httpClientReqVar, HTTP_NAME_CLOSENOW, jsvNewFromBool(true))); } else { jsvUnLock(jsvObjectSetChild(httpClientReqVar, HTTP_NAME_SOCKET, jsvNewFromInteger(sckt+1))); // For HTTP we get the connection callback when we've got a header back // Otherwise we just call back on success if (socketType != ST_HTTP) { jsiQueueObjectCallbacks(httpClientReqVar, HTTP_NAME_ON_CONNECT, &httpClientReqVar, 1); } } jsvUnLock(options); net->checkError(net); }
IOEventFlags jshPinWatch( Pin pin, //!< Unknown bool shouldWatch //!< Unknown ) { if (jshIsPinValid(pin)) { } else jsError("Invalid pin!"); return EV_NONE; }
bool jshPinInput(Pin pin) { bool value = false; if (jshIsPinValid(pin)) { jshPinSetState(pin, JSHPINSTATE_GPIO_IN); value = jshPinGetValue(pin); } else jsError("Invalid pin!"); return value; }