Пример #1
0
/**
 * Invoke the JavaScript callback to notify the program that an ESP8266
 * WiFi event has occurred.
 */
static void sendWifiEvent(
    uint32 eventType, //!< The ESP8266 WiFi event type.
    JsVar *jsDetails  //!< The JS object to be passed as a parameter to the callback.
  ) {
  jsvUnLock(jsDetails);

  // We need to check that we actually have an event callback handler because
  // it might have been disabled/removed.
  if (g_jsWiFiEventCallback != NULL) {
    // Build a callback event.
    JsVar *params[2];
    params[0] = jsvNewFromInteger(eventType);
    params[1] = jsDetails;
    jsiQueueEvents(NULL, g_jsWiFiEventCallback, params, 2);
  }

  if (g_jsGotIpCallback != NULL && eventType == EVENT_STAMODE_GOT_IP) {
    JsVar *params[2];
    params[0] = jsvNewFromInteger(eventType);
    params[1] = jsDetails;
    jsiQueueEvents(NULL, g_jsGotIpCallback, params, 2);
    // Once we have registered the callback, we can unlock and release
    // the variable as we are only calling it once.
    //jsvUnLock(jsGotIpCallback);
    //jsGotIpCallback = NULL;
  }
}
Пример #2
0
void _jswrap_promise_queuereject(JsVar *promise, JsVar *data) {
  JsVar *fn = jsvNewNativeFunction((void (*)(void))_jswrap_promise_reject, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS));
  if (!fn) return;
  jsvObjectSetChild(fn, JSPARSE_FUNCTION_THIS_NAME, promise);
  jsiQueueEvents(promise, fn, &data, 1);
  jsvUnLock(fn);
}
Пример #3
0
/**
 * Handle receiving a response from a ping reply.
 * If a callback function has been supplied we invoked that callback by queuing it for future
 * execution.  A parameter is supplied to the callback which is a JavaScript object that contains:
 *  - totalCount
 *  - totalBytes
 *  - totalTime
 *  - respTime
 *  - seqNo
 *  - timeoutCount
 *  - bytes
 *  - error
 */
static void pingRecvCB(void *pingOpt, void *pingResponse) {
  struct ping_resp *pingResp = (struct ping_resp *)pingResponse;
  os_printf("Received a ping response!\n");
  if (g_jsPingCallback != NULL) {
    JsVar *jsPingResponse = jspNewObject(NULL, "PingResponse");
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "totalCount",   jsvNewFromInteger(pingResp->total_count)));
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "totalBytes",   jsvNewFromInteger(pingResp->total_bytes)));
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "totalTime",    jsvNewFromInteger(pingResp->total_time)));
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "respTime",     jsvNewFromInteger(pingResp->resp_time)));
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "seqNo",        jsvNewFromInteger(pingResp->seqno)));
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "timeoutCount", jsvNewFromInteger(pingResp->timeout_count)));
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "bytes",        jsvNewFromInteger(pingResp->bytes)));
    jsvUnLock(jsvObjectSetChild(jsPingResponse, "error",        jsvNewFromInteger(pingResp->ping_err)));
    JsVar *params[1];
    params[0] = jsPingResponse;
    jsiQueueEvents(NULL, g_jsPingCallback, params, 1);
  }
}
Пример #4
0
/*JSON{
  "type" : "method",
  "class" : "ESPWifi",
  "name" : "connect",
  "generate" : "jswrap_esp8266_connect",
  "params" : [
    ["ap","JsVar","Access point name"],
    ["key","JsVar","WPA2 key (or undefined for unsecured connection)"],
    ["callback","JsVar","Function to call back with connection status. It has one argument which is one of 'connect'/'disconnect'/'dhcp'"]
  ],
  "return" : ["bool",""]
}
Connect to an access point
*/
bool jswrap_esp8266_connect(JsVar *wlanObj, JsVar *vAP, JsVar *vKey, JsVar *callback) {
  NOT_USED(wlanObj);

  JsNetwork net;
  if (!networkGetFromVar(&net)) return false;
  // 'AT+CWMODE=1\r' ? seems to be the default
  JsVar *msg = jsvVarPrintf("AT+CWJAP=%q,%q\r", vAP, vKey);
  esp8266_send(msg);
  jsvUnLock(msg);
  if (!esp8266_wait_for("OK",500, false))
    return false;

  networkFree(&net);

  if (callback)
    jsiQueueEvents(callback, 0, 0);

  return true;
}
Пример #5
0
/*JSON{
  "type" : "staticmethod",
  "class" : "ESP8266",
  "name" : "connect",
  "generate" : "jswrap_esp8266_connect_device",
  "params" : [
    ["serial","JsVar","The Serial port used for communications with the ESP8266 (must already be setup)"],
    ["callback","JsVar","Function to call back when connected"]
  ],
  "return" : ["JsVar","An ESP8266 Object"],
  "return_object" : "ESP8266"
}
Initialise the WIZnet module and return an Ethernet object
*/
JsVar *jswrap_esp8266_connect_device(JsVar *usart, JsVar *callback) {

  IOEventFlags usartDevice;
  usartDevice = jsiGetDeviceFromClass(usart);
  if (!DEVICE_IS_USART(usartDevice)) {
    jsExceptionHere(JSET_ERROR, "Expecting USART device, got %q", usart);
    return 0;
  }

  JsNetwork net;
  networkCreate(&net, JSNETWORKTYPE_ESP8266);
  net.data.device = usartDevice;
  networkSet(&net);

  JsVar *wifiObj = 0;

  JsVar *cmd = jsvNewFromString("AT+RST\r\n");
  esp8266_send(cmd);
  jsvUnLock(cmd);
  if (esp8266_wait_for("OK", 100, false)) {
    if (esp8266_wait_for("ready", 4000, false)) {
      networkState = NETWORKSTATE_ONLINE;
      wifiObj = jspNewObject(0, "ESPWifi");
    } else {
      jsExceptionHere(JSET_ERROR, "Module not ready");
    }
  } else {
    jsExceptionHere(JSET_ERROR, "No Acknowledgement");
  }


  networkFree(&net);

  if (callback)
    jsiQueueEvents(callback, 0, 0);

  return wifiObj;
}
Пример #6
0
/*JSON{
  "type" : "method",
  "class" : "Object",
  "name" : "emit",
  "generate" : "jswrap_object_emit",
  "params" : [
    ["event","JsVar","The name of the event, for instance 'data'"],
    ["args","JsVarArray","Optional arguments"]
  ]
}
Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter.
 */
void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *argArray) {
  if (!jsvHasChildren(parent)) {
    jsWarn("Parent must be an object - not a String, Integer, etc.");
    return;
  }
  if (!jsvIsString(event)) {
    jsWarn("First argument to EventEmitter.emit(..) must be a string");
    return;
  }
  JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event);
  if (!eventName) return; // no memory

  // extract data
  const unsigned int MAX_ARGS = 4;
  JsVar *args[MAX_ARGS];
  unsigned int n = 0;
  JsvObjectIterator it;
  jsvObjectIteratorNew(&it, argArray);
  while (jsvObjectIteratorHasValue(&it)) {
    if (n>=MAX_ARGS) {
      jsWarn("Too many arguments");
      break;
    }
    args[n++] = jsvObjectIteratorGetValue(&it);
    jsvObjectIteratorNext(&it);
  }
  jsvObjectIteratorFree(&it);


  JsVar *callback = jsvSkipNameAndUnLock(jsvFindChildFromVar(parent, eventName, 0));
  jsvUnLock(eventName);
  if (callback) jsiQueueEvents(parent, callback, args, (int)n);
  jsvUnLock(callback);

  // unlock
  jsvUnLockMany(n, args);
}
Пример #7
0
/*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;
}
Пример #8
0
/*JSON{
  "type"     : "staticmethod",
  "class"    : "ESP8266WiFi",
  "name"     : "connect",
  "generate" : "jswrap_ESP8266WiFi_connect",
  "params"   : [
    ["ssid","JsVar","The network id of the access point."],
    ["password","JsVar","The password to the access point"],
    ["gotIpCallback", "JsVar", "An optional callback invoked when we have an IP"]
  ]
}
 *
 * Connect the station to an access point.
 */
void jswrap_ESP8266WiFi_connect(
    JsVar *jsv_ssid,     //!< The SSID of the access point to connect.
    JsVar *jsv_password, //!< The password for the access point.
    JsVar *gotIpCallback //!< The Callback function to be called when we are connected.
  ) {
    os_printf("> jswrap_ESP8266WiFi_connect\n");

  // Check that the ssid and password values aren't obviously in error.
  if (jsv_ssid == NULL || !jsvIsString(jsv_ssid)) {
      jsExceptionHere(JSET_ERROR, "No SSID.");
    return;
  }
  if (jsv_password == NULL || !jsvIsString(jsv_password)) {
      jsExceptionHere(JSET_ERROR, "No password.");
    return;
  }

  // Check that if a callback function was supplied that we actually have a callback function.
  if (gotIpCallback != NULL && !jsvIsUndefined(gotIpCallback) && !jsvIsFunction(gotIpCallback)) {
    gotIpCallback = NULL;
      jsExceptionHere(JSET_ERROR, "A callback function was supplied that is not a function.");
    return;
  }
  if (jsvIsUndefined(gotIpCallback) || jsvIsNull(gotIpCallback)) {
    gotIpCallback = NULL;
  }

  // Set the global which is the gotIP callback to null but first unlock it.
  if (g_jsGotIpCallback != NULL) {
    jsvUnLock(g_jsGotIpCallback);
    g_jsGotIpCallback = NULL;
  }

  // If we have a callback, save it for later invocation.
  if (gotIpCallback != NULL) {
    g_jsGotIpCallback = jsvLockAgainSafe(gotIpCallback);
  }

  // Debug
  // os_printf("jsGotIpCallback=%p\n", jsGotIpCallback);

  // Create strings from the JsVars for the ESP8266 API calls.
  char ssid[33];
  int len = jsvGetString(jsv_ssid, ssid, sizeof(ssid)-1);
  ssid[len]='\0';
  char password[65];
  len = jsvGetString(jsv_password, password, sizeof(password)-1);
  password[len]='\0';

  os_printf(">  - ssid=%s, password=%s\n", ssid, password);

  // Set the WiFi mode of the ESP8266
  wifi_set_opmode_current(STATION_MODE);

  struct station_config stationConfig;
  memset(&stationConfig, 0, sizeof(stationConfig));
  os_strncpy((char *)stationConfig.ssid, ssid, 32);
  if (password != NULL) {
    os_strncpy((char *)stationConfig.password, password, 64);
  } else {
    os_strcpy((char *)stationConfig.password, "");
  }

  // Set the WiFi configuration
  wifi_station_set_config(&stationConfig);

  uint8 wifiConnectStatus = wifi_station_get_connect_status();
  os_printf(" - Current connect status: %s\n", wifiConnectStatusToString(wifiConnectStatus));

  if (wifiConnectStatus == STATION_GOT_IP) {
    // See issue #618.  There are currently three schools of thought on what should happen
    // when a connect is issued and we are already connected.
    //
    // Option #1 - Always perform a disconnect.
    // Option #2 - Perform a disconnect if the SSID or PASSWORD are different from current
    // Option #3 - Fail the connect if we are already connected.
    //
#define ISSUE_618 1

#if ISSUE_618 == 1
    wifi_station_disconnect();
#elif ISSUE_618 == 2
    struct station_config existingConfig;
    wifi_station_get_config(&existingConfig);
    if (os_strncmp((char *)existingConfig.ssid, (char *)stationConfig.ssid, 32) == 0 &&
        os_strncmp((char *)existingConfig.password, (char *)stationConfig.password, 64) == 0) {
      if (jsGotIpCallback != NULL) {
        JsVar *params[2];
        params[0] = jsvNewFromInteger(STATION_GOT_IP);
         params[1] = jsvNewNull();
        jsiQueueEvents(NULL, jsGotIpCallback, params, 2);
      }
      return;

    } else {
      wifi_station_disconnect();
    }
#elif ISSUE_618 == 3
    // Add a return code to the function and return an already connected error.
#endif
  }
  // Perform the network level connection.
  wifi_station_connect();
  os_printf("< jswrap_ESP8266WiFi_connect\n");
}
Пример #9
0
/**
 * 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");
}
Пример #10
0
/*JSON{
  "type" : "method",
  "class" : "Ethernet",
  "name" : "setIP",
  "generate" : "jswrap_ethernet_setIP",
  "params" : [
    ["options","JsVar","Object containing IP address options `{ ip : '1,2,3,4', subnet, gateway, dns, mac  }`, or do not supply an object in order to force DHCP."],
    ["options","JsVar","An optional `callback(err)` function to invoke when ip is set. `err==null` on success, or a string on failure."]
  ],
  "return" : ["bool","True on success"]
}
Set the current IP address or get an IP from DHCP (if no options object is specified)

If 'mac' is specified as an option, it must be a string of the form `"00:01:02:03:04:05"`
*/
bool jswrap_ethernet_setIP(JsVar *wlanObj, JsVar *options, JsVar *callback) {
  NOT_USED(wlanObj);

  if (networkState != NETWORKSTATE_ONLINE) {
    jsExceptionHere(JSET_ERROR, "Not connected to the internet");
    return false;
  }

  JsNetwork net;
  if (!networkGetFromVar(&net)) return false;

  const char *errorMessage = 0;
  wiz_NetInfo gWIZNETINFO;

  ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
  if (!gWIZNETINFO.mac[0] && !gWIZNETINFO.mac[1] &&
      !gWIZNETINFO.mac[2] && !gWIZNETINFO.mac[3] &&
      !gWIZNETINFO.mac[4] && !gWIZNETINFO.mac[5]) {
    // wow - no mac address - WIZ550BoB? Set up a simple one
    // in WIZnet's range of addresses
    gWIZNETINFO.mac[0]=0x00;
    gWIZNETINFO.mac[1]=0x08;
    gWIZNETINFO.mac[2]=0xDC;
    gWIZNETINFO.mac[3]=0x01;
    gWIZNETINFO.mac[4]=0x02;
    gWIZNETINFO.mac[5]=0x03;
  }

  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]);

    JsVar *info = jsvObjectGetChild(options, "mac", 0);
    if (info) {
      char buf[64];
      jsvGetString(info, buf, sizeof(buf));
      networkParseMACAddress(&gWIZNETINFO.mac[0], buf);
      // TODO: check failure?
      jsvUnLock(info);
    }

    gWIZNETINFO.dhcp = NETINFO_STATIC;
    errorMessage = 0; // all ok
  } else {
    // DHCP
    uint8_t DHCPisSuccess = getIP_DHCPS(net_wiznet_getFreeSocket(), &gWIZNETINFO);
    if (DHCPisSuccess == 1) {
      // info in lease_time.lVal
      errorMessage = 0; // all ok
    } else {
      errorMessage = "DHCP failed";
      jsWarn(errorMessage);
    }
  }

  ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);

  networkFree(&net);

  // Schedule callback if a function was provided
  if (jsvIsFunction(callback)) {
    JsVar *params[1];
    params[0] = errorMessage ? jsvNewFromString(errorMessage) : jsvNewWithFlags(JSV_NULL);
    jsiQueueEvents(NULL, callback, params, 1);
    jsvUnLock(params[0]);
  }

  return errorMessage==0;
}