mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
1202 lines
36 KiB
C
1202 lines
36 KiB
C
/*
|
|
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
|
*
|
|
* Copyright (C) 2015 Gordon Williams <gw@pur3.co.uk>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
* This file is designed to be parsed during the build process
|
|
*
|
|
* Contains ESP32 and Wifi library specific functions.
|
|
*
|
|
* FOR DESCRIPTIONS OF THE WIFI FUNCTIONS IN THIS FILE, SEE
|
|
* libs/network/jswrap_wifi.c (or http://www.espruino.com/Reference#Wifi)
|
|
*
|
|
* IMPORTANT: the functions in this file have tests in ./tests/wifi-test-mode.js
|
|
* please maintain these tests if you make functional changes!
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
// Includes from ESP-IDF
|
|
#include "esp_wifi.h"
|
|
#include "esp_event_loop.h"
|
|
#include "tcpip_adapter.h"
|
|
|
|
#include "jsinteractive.h"
|
|
#include "network.h"
|
|
#include "jswrap_modules.h"
|
|
#include "jswrap_esp32_network.h"
|
|
|
|
#include "jsutils.h"
|
|
|
|
#define UNUSED(x) (void)(x)
|
|
|
|
static void sendWifiCompletionCB(
|
|
JsVar **g_jsCallback, //!< Pointer to the global callback variable
|
|
char *reason //!< NULL if successful, error string otherwise
|
|
);
|
|
|
|
// A callback function to be invoked on a disconnect response.
|
|
static JsVar *g_jsDisconnectCallback;
|
|
|
|
// A callback function to be invoked when we have an IP address.
|
|
static JsVar *g_jsGotIpCallback;
|
|
|
|
// A callback function to be invoked when we complete an access point scan.
|
|
static JsVar *g_jsScanCallback;
|
|
|
|
// A callback function to be invoked when we are being an access point.
|
|
static JsVar *g_jsAPStartedCallback;
|
|
|
|
// The last time we were connected as a station.
|
|
static system_event_sta_connected_t g_lastEventStaConnected;
|
|
|
|
// The last time we were disconnected as a station.
|
|
static system_event_sta_disconnected_t g_lastEventStaDisconnected;
|
|
|
|
// Are we connected as a station?
|
|
static bool g_isStaConnected = false;
|
|
|
|
#define EXPECT_CB_EXCEPTION(jsCB) jsExceptionHere(JSET_ERROR, "Expecting callback function but got %v", jsCB)
|
|
#define EXPECT_OPT_EXCEPTION(jsOPT) jsExceptionHere(JSET_ERROR, "Expecting options object but got %t", jsOPT)
|
|
|
|
|
|
/**
|
|
* Convert an wifi_auth_mode_t data type to a string value.
|
|
*/
|
|
static char *authModeToString(wifi_auth_mode_t authMode) {
|
|
|
|
switch(authMode) {
|
|
case WIFI_AUTH_OPEN:
|
|
return "open";
|
|
case WIFI_AUTH_WEP:
|
|
return "wep";
|
|
case WIFI_AUTH_WPA_PSK:
|
|
return "wpa";
|
|
case WIFI_AUTH_WPA2_PSK:
|
|
return "wpa2";
|
|
case WIFI_AUTH_WPA_WPA2_PSK:
|
|
return "wpa_wpa2";
|
|
}
|
|
return "unknown";
|
|
} // End of authModeToString
|
|
|
|
|
|
/**
|
|
* Convert a Wifi reason code to a string representation.
|
|
*/
|
|
static char *wifiReasonToString(uint8_t reason) {
|
|
switch(reason) {
|
|
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
|
|
return "4WAY_HANDSHAKE_TIMEOUT";
|
|
case WIFI_REASON_802_1X_AUTH_FAILED:
|
|
return "802_1X_AUTH_FAILED";
|
|
case WIFI_REASON_AKMP_INVALID:
|
|
return "AKMP_INVALID";
|
|
case WIFI_REASON_ASSOC_EXPIRE:
|
|
return "ASSOC_EXPIRE";
|
|
case WIFI_REASON_ASSOC_FAIL:
|
|
return "ASSOC_FAIL";
|
|
case WIFI_REASON_ASSOC_LEAVE:
|
|
return "ASSOC_LEAVE";
|
|
case WIFI_REASON_ASSOC_NOT_AUTHED:
|
|
return "ASSOC_NOT_AUTHED";
|
|
case WIFI_REASON_ASSOC_TOOMANY:
|
|
return "ASSOC_TOOMANY";
|
|
case WIFI_REASON_AUTH_EXPIRE:
|
|
return "AUTH_EXPIRE";
|
|
case WIFI_REASON_AUTH_FAIL:
|
|
return "AUTH_FAIL";
|
|
case WIFI_REASON_AUTH_LEAVE:
|
|
return "AUTH_LEAVE";
|
|
case WIFI_REASON_BEACON_TIMEOUT:
|
|
return "BEACON_TIMEOUT";
|
|
case WIFI_REASON_CIPHER_SUITE_REJECTED:
|
|
return "CIPHER_SUITE_REJECTED";
|
|
case WIFI_REASON_DISASSOC_PWRCAP_BAD:
|
|
return "DISASSOC_PWRCAP_BAD";
|
|
case WIFI_REASON_DISASSOC_SUPCHAN_BAD:
|
|
return "DISASSOC_SUPCHAN_BAD";
|
|
case WIFI_REASON_GROUP_CIPHER_INVALID:
|
|
return "GROUP_CIPHER_INVALID";
|
|
case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT:
|
|
return "GROUP_KEY_UPDATE_TIMEOUT";
|
|
case WIFI_REASON_HANDSHAKE_TIMEOUT:
|
|
return "HANDSHAKE_TIMEOUT";
|
|
case WIFI_REASON_IE_INVALID:
|
|
return "IE_INVALID";
|
|
case WIFI_REASON_IE_IN_4WAY_DIFFERS:
|
|
return "IE_IN_4WAY_DIFFERS";
|
|
case WIFI_REASON_INVALID_RSN_IE_CAP:
|
|
return "INVALID_RSN_IE_CAP";
|
|
case WIFI_REASON_MIC_FAILURE:
|
|
return "MIC_FAILURE";
|
|
case WIFI_REASON_NOT_ASSOCED:
|
|
return "NOT_ASSOCED";
|
|
case WIFI_REASON_NOT_AUTHED:
|
|
return "NOT_AUTHED";
|
|
case WIFI_REASON_NO_AP_FOUND:
|
|
return "NO_AP_FOUND";
|
|
case WIFI_REASON_PAIRWISE_CIPHER_INVALID:
|
|
return "PAIRWISE_CIPHER_INVALID";
|
|
case WIFI_REASON_UNSPECIFIED:
|
|
return "UNSPECIFIED";
|
|
case WIFI_REASON_UNSUPP_RSN_IE_VERSION:
|
|
return "REASON_UNSUPP_RSN_IE_VERSION";
|
|
}
|
|
jsWarn( "wifiReasonToString: Unknown reasonL %d", reason);
|
|
return "Unknown reason";
|
|
} // End of wifiReasonToString
|
|
|
|
/**
|
|
* Convery a wifi_mode_t data type to a string value.
|
|
*/
|
|
static char *wifiModeToString(wifi_mode_t mode) {
|
|
switch(mode) {
|
|
case WIFI_MODE_NULL:
|
|
return "NULL";
|
|
case WIFI_MODE_STA:
|
|
return "STA";
|
|
case WIFI_MODE_AP:
|
|
return "AP";
|
|
case WIFI_MODE_APSTA:
|
|
return "APSTA";
|
|
}
|
|
return "UNKNOWN";
|
|
} // End of wifiModeToString
|
|
|
|
|
|
/**
|
|
* Callback function that is invoked at the culmination of a scan.
|
|
*/
|
|
static void scanCB() {
|
|
/**
|
|
* 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.
|
|
*/
|
|
|
|
if (g_jsScanCallback == NULL) {
|
|
return;
|
|
}
|
|
|
|
|
|
uint16_t apCount;
|
|
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&apCount));
|
|
|
|
JsVar *jsAccessPointArray = jsvNewArray(NULL, 0);
|
|
if (apCount > 0) {
|
|
wifi_ap_record_t *list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);
|
|
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, list));
|
|
|
|
int i;
|
|
for (i=0; i<apCount; i++) {
|
|
JsVar *jsCurrentAccessPoint = jsvNewObject();
|
|
jsvObjectSetChildAndUnLock(jsCurrentAccessPoint, "rssi", jsvNewFromInteger(list[i].rssi));
|
|
jsvObjectSetChildAndUnLock(jsCurrentAccessPoint, "authMode", jsvNewFromString(authModeToString(list[i].authmode)));
|
|
|
|
// The SSID may **NOT** be NULL terminated ... so handle that.
|
|
char ssid[32 + 1];
|
|
strncpy((char *)ssid, list[i].ssid, 32);
|
|
ssid[32] = '\0';
|
|
jsvObjectSetChildAndUnLock(jsCurrentAccessPoint, "ssid", jsvNewFromString(ssid));
|
|
|
|
/*
|
|
char macAddrString[6*3 + 1];
|
|
os_sprintf(macAddrString, macFmt,
|
|
bssInfo->bssid[0], bssInfo->bssid[1], bssInfo->bssid[2],
|
|
bssInfo->bssid[3], bssInfo->bssid[4], bssInfo->bssid[5]);
|
|
jsvObjectSetChildAndUnLock(jsCurrentAccessPoint, "mac", jsvNewFromString(macAddrString));
|
|
*/
|
|
|
|
// Add the new record to the array
|
|
jsvArrayPush(jsAccessPointArray, jsCurrentAccessPoint);
|
|
jsvUnLock(jsCurrentAccessPoint);
|
|
} // End of loop over each access point
|
|
free(list);
|
|
} // Number of access points > 0
|
|
|
|
// We have now completed the scan callback, so now we can invoke the JS callback.
|
|
JsVar *params[1];
|
|
params[0] = jsAccessPointArray;
|
|
jsiQueueEvents(NULL, g_jsScanCallback, params, 1);
|
|
|
|
jsvUnLock(jsAccessPointArray);
|
|
jsvUnLock(g_jsScanCallback);
|
|
g_jsScanCallback = NULL;
|
|
} // End of scanCB
|
|
|
|
|
|
/** Get the global object for the Wifi library/module, this is used in order to send the
|
|
* "on event" callbacks to the handlers.
|
|
*/
|
|
static JsVar *getWifiModule() {
|
|
JsVar *moduleName = jsvNewFromString("Wifi");
|
|
JsVar *m = jswrap_require(moduleName);
|
|
jsvUnLock(moduleName);
|
|
return m;
|
|
} // End of getWifiModule
|
|
|
|
/**
|
|
* Given an ESP32 WiFi event type, determine the corresponding
|
|
* event handler name we should publish upon. For example, if we
|
|
* have an event of type "SYSTEM_EVENT_STA_CONNECTED" then we wish
|
|
* to publish an event upon "#onassociated". The implementation
|
|
* here is a simple switch as at this time we don't want to assume
|
|
* anything about the values of event types (i.e. whether they are small
|
|
* and sequential). If we could make assumptions about the event
|
|
* types we may have been able to use a lookup array.
|
|
*
|
|
* The mappings are:
|
|
* SYSTEM_EVENT_AP_PROBEREQRECVED - #onprobe_recv
|
|
* SYSTEM_EVENT_AP_STACONNECTED - #onsta_joined
|
|
* SYSTEM_EVENT_AP_STADISCONNECTED - #onsta_left
|
|
* SYSTEM_EVENT_STA_AUTHMODE_CHANGE - #onauth_change
|
|
* SYSTEM_EVENT_STA_CONNECTED - #onassociated
|
|
* SYSTEM_EVENT_STA_DISCONNECTED - #ondisconnected
|
|
* SYSTEM_EVENT_STA_GOT_IP - #onconnected
|
|
*
|
|
* See also:
|
|
* * event_handler()
|
|
*
|
|
*/
|
|
static char *wifiGetEvent(uint32_t event) {
|
|
switch(event) {
|
|
case SYSTEM_EVENT_AP_PROBEREQRECVED:
|
|
return "#onprobe_recv";
|
|
case SYSTEM_EVENT_AP_STACONNECTED:
|
|
return "#onsta_joined";
|
|
case SYSTEM_EVENT_AP_STADISCONNECTED:
|
|
return "#onsta_left";
|
|
case SYSTEM_EVENT_AP_START:
|
|
break;
|
|
case SYSTEM_EVENT_AP_STOP:
|
|
break;
|
|
case SYSTEM_EVENT_SCAN_DONE:
|
|
break;
|
|
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
|
|
return "#onauth_change";
|
|
case SYSTEM_EVENT_STA_CONNECTED:
|
|
return "#onassociated";
|
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
|
return "#ondisconnected";
|
|
case SYSTEM_EVENT_STA_GOT_IP:
|
|
return "#onconnected";
|
|
case SYSTEM_EVENT_STA_START:
|
|
break;
|
|
case SYSTEM_EVENT_STA_STOP:
|
|
break;
|
|
case SYSTEM_EVENT_WIFI_READY:
|
|
break;
|
|
}
|
|
jsWarn( "Unhandled wifi event type: %d", event);
|
|
return NULL;
|
|
} // End of wifiGetEvent
|
|
|
|
/**
|
|
* Invoke the JavaScript callback to notify the program that an ESP8266
|
|
* WiFi event has occurred.
|
|
*/
|
|
static void sendWifiEvent(
|
|
uint32_t eventType, //!< The ESP32 WiFi event type.
|
|
JsVar *jsDetails //!< The JS object to be passed as a parameter to the callback.
|
|
) {
|
|
JsVar *module = getWifiModule();
|
|
if (!module) {
|
|
return; // out of memory?
|
|
}
|
|
|
|
// get event name as string and compose param list
|
|
JsVar *params[1];
|
|
params[0] = jsDetails;
|
|
char *eventName = wifiGetEvent(eventType);
|
|
if (eventName == NULL) {
|
|
return;
|
|
}
|
|
|
|
jsiQueueObjectCallbacks(module, eventName, params, 1);
|
|
jsvUnLock(module);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Wifi event handler
|
|
* Here we get invoked whenever a WiFi event is received from the ESP32 WiFi
|
|
* subsystem. The events include:
|
|
* * SYSTEM_EVENT_STA_DISCONNECTED - As a station, we were disconnected.
|
|
*/
|
|
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
|
{
|
|
UNUSED(ctx);
|
|
/*
|
|
* SYSTEM_EVENT_STA_DISCONNECT
|
|
* Structure contains:
|
|
* * ssid
|
|
* * ssid_len
|
|
* * bssid
|
|
* * reason
|
|
*/
|
|
if (event->event_id == SYSTEM_EVENT_STA_DISCONNECTED) {
|
|
g_isStaConnected = false; // Flag us as disconnected
|
|
g_lastEventStaDisconnected = event->event_info.disconnected; // Save the last disconnected info
|
|
|
|
if (jsvIsFunction(g_jsDisconnectCallback)) {
|
|
jsiQueueEvents(NULL, g_jsDisconnectCallback, NULL, 0);
|
|
jsvUnLock(g_jsDisconnectCallback);
|
|
g_jsDisconnectCallback = NULL;
|
|
}
|
|
JsVar *jsDetails = jsvNewObject();
|
|
|
|
char temp[33];
|
|
memcpy(temp, event->event_info.disconnected.ssid, 32);
|
|
temp[32] = '\0';
|
|
jsvObjectSetChildAndUnLock(jsDetails, "ssid", jsvNewFromString(temp));
|
|
sprintf(temp, MACSTR, MAC2STR(event->event_info.disconnected.bssid));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "mac", jsvNewFromString(temp));
|
|
sprintf(temp, "%d", event->event_info.disconnected.reason);
|
|
jsvObjectSetChildAndUnLock(jsDetails, "reason", jsvNewFromString(temp));
|
|
sendWifiEvent(event->event_id, jsDetails);
|
|
return ESP_OK;
|
|
} // End of handle SYSTEM_EVENT_STA_DISCONNECTED
|
|
|
|
/**
|
|
* SYSTEM_EVENT_STA_CONNECTED
|
|
* Structure contains:
|
|
* * ssid
|
|
* * ssid_len
|
|
* * bssid
|
|
* * channel
|
|
* * authmode
|
|
*/
|
|
if (event->event_id == SYSTEM_EVENT_STA_CONNECTED) {
|
|
g_isStaConnected = true; // Flag us as connected.
|
|
g_lastEventStaConnected = event->event_info.connected; // Save the last connected info
|
|
|
|
// Publish the on("associated") event to any one who has registered
|
|
// an interest.
|
|
JsVar *jsDetails = jsvNewObject();
|
|
|
|
char temp[33];
|
|
memcpy(temp, event->event_info.connected.ssid, 32);
|
|
temp[32] = '\0';
|
|
jsvObjectSetChildAndUnLock(jsDetails, "ssid", jsvNewFromString(temp));
|
|
sprintf(temp, MACSTR, MAC2STR(event->event_info.connected.bssid));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "mac", jsvNewFromString(temp));
|
|
sprintf(temp, "%d", event->event_info.connected.channel);
|
|
jsvObjectSetChildAndUnLock(jsDetails, "channel", jsvNewFromString(temp));
|
|
sendWifiEvent(event->event_id, jsDetails);
|
|
return ESP_OK;
|
|
} // End of handle SYSTEM_EVENT_STA_CONNECTED
|
|
|
|
|
|
/**
|
|
* SYSTEM_EVENT_STA_GOT_IP
|
|
* Structure contains:
|
|
* * ipinfo.ip
|
|
* * ipinfo.netmask
|
|
* * ip_info.gw
|
|
*/
|
|
if (event->event_id == SYSTEM_EVENT_STA_GOT_IP) {
|
|
sendWifiCompletionCB(&g_jsGotIpCallback, NULL);
|
|
JsVar *jsDetails = jsvNewObject();
|
|
|
|
// 123456789012345_6
|
|
// xxx.xxx.xxx.xxx\0
|
|
char temp[16];
|
|
sprintf(temp, IPSTR, IP2STR(&event->event_info.got_ip.ip_info.ip));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "ip", jsvNewFromString(temp));
|
|
sprintf(temp, IPSTR, IP2STR(&event->event_info.got_ip.ip_info.netmask));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "netmask", jsvNewFromString(temp));
|
|
sprintf(temp, IPSTR, IP2STR(&event->event_info.got_ip.ip_info.gw));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "gw", jsvNewFromString(temp));
|
|
|
|
sendWifiEvent(event->event_id, jsDetails);
|
|
return ESP_OK;
|
|
} // End of handle SYSTEM_EVENT_STA_GOT_IP
|
|
|
|
|
|
/**
|
|
* SYSTEM_EVENT_AP_STACONNECTED
|
|
* Structure contains:
|
|
* * mac
|
|
* * aid
|
|
*/
|
|
if (event->event_id == SYSTEM_EVENT_AP_STACONNECTED) {
|
|
JsVar *jsDetails = jsvNewObject();
|
|
// 12345678901234567_8
|
|
// xx:xx:xx:xx:xx:xx\0
|
|
char temp[18];
|
|
sprintf(temp, MACSTR, MAC2STR(&event->event_info.sta_connected.mac));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "mac", jsvNewFromString(temp));
|
|
sendWifiEvent(event->event_id, jsDetails);
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* SYSTEM_EVENT_AP_STADISCONNECTED
|
|
* Structure contains:
|
|
* * mac
|
|
* * aid
|
|
*/
|
|
if (event->event_id == SYSTEM_EVENT_AP_STADISCONNECTED) {
|
|
JsVar *jsDetails = jsvNewObject();
|
|
// 12345678901234567_8
|
|
// xx:xx:xx:xx:xx:xx\0
|
|
char temp[18];
|
|
sprintf(temp, MACSTR, MAC2STR(&event->event_info.sta_disconnected.mac));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "mac", jsvNewFromString(temp));
|
|
sendWifiEvent(event->event_id, jsDetails);
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* SYSTEM_EVENT_SCAN_DONE
|
|
* Called when a previous network scan has completed. Here we check to see if we have
|
|
* a registered callback that is interested in being called when a scan has completed
|
|
* and, if we do, we build the parameters for that callback and then invoke it.
|
|
*/
|
|
if (event->event_id == SYSTEM_EVENT_SCAN_DONE) {
|
|
scanCB();
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* SYSTEM_EVENT_AP_START
|
|
* Called when we have started being an access point.
|
|
*/
|
|
if (event->event_id == SYSTEM_EVENT_AP_START) {
|
|
sendWifiCompletionCB(&g_jsAPStartedCallback, NULL);
|
|
return ESP_OK;
|
|
}
|
|
|
|
return ESP_OK;
|
|
} // End of event_handler
|
|
|
|
|
|
/**
|
|
* Initialize the one time ESP32 wifi components including the event
|
|
* handler.
|
|
*/
|
|
void esp32_wifi_init() {
|
|
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL));
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
|
|
|
|
} // End of esp32_wifi_init
|
|
|
|
|
|
/**
|
|
* Some of the WiFi functions have a completion callback which is of the form:
|
|
* function(err) { ... }
|
|
* These callbacks are called with an error string (if an error is encountered) or null if there is
|
|
* no error. Since this occurrence happens a number of times, this helper function takes as input
|
|
* a pointer to a callback function and a parameter.
|
|
*/
|
|
static void sendWifiCompletionCB(
|
|
JsVar **g_jsCallback, //!< Pointer to the global callback variable
|
|
char *reason //!< NULL if successful, error string otherwise
|
|
) {
|
|
// Check that we have a callback function.
|
|
if (!jsvIsFunction(*g_jsCallback)){
|
|
return; // we have not got a function pointer: nothing to do
|
|
}
|
|
|
|
JsVar *params[1];
|
|
params[0] = reason ? jsvNewFromString(reason) : jsvNewNull();
|
|
jsiQueueEvents(NULL, *g_jsCallback, params, 1);
|
|
jsvUnLock(params[0]);
|
|
// unlock and delete the global callback
|
|
jsvUnLock(*g_jsCallback);
|
|
*g_jsCallback = NULL;
|
|
} // End of sendWifiCompletionCB
|
|
|
|
/*JSON{
|
|
"type":"init",
|
|
"generate":"jswrap_esp32_wifi_soft_init"
|
|
}
|
|
|
|
/**
|
|
* Perform a soft initialization of ESP32 networking.
|
|
*/
|
|
void jswrap_esp32_wifi_soft_init() {
|
|
JsNetwork net;
|
|
networkCreate(&net, JSNETWORKTYPE_ESP32); // Set the network type to be ESP32
|
|
networkState = NETWORKSTATE_ONLINE; // Set the global state of the networking to be online
|
|
}
|
|
|
|
void jswrap_wifi_disconnect(JsVar *jsCallback) {
|
|
// We save the callback function so that it can subsequently invoked. Then we execute the
|
|
// ESP-IDF function to disconnect us from the access point. The thinking is that will result
|
|
// in a subsequent event which we will detect and use to call the callback.
|
|
//
|
|
// Free any existing callback, then register new callback
|
|
if (g_jsDisconnectCallback != NULL) jsvUnLock(g_jsDisconnectCallback);
|
|
g_jsDisconnectCallback = NULL;
|
|
|
|
// Check that the callback is a good callback if supplied.
|
|
if (jsCallback != NULL && !jsvIsUndefined(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return;
|
|
}
|
|
|
|
// Save the callback for later execution.
|
|
g_jsDisconnectCallback = jsvLockAgainSafe(jsCallback);
|
|
|
|
// Call the ESP-IDF to disconnect us from the access point.
|
|
esp_wifi_disconnect();
|
|
} // End of jswrap_wifi_disconnect
|
|
|
|
void jswrap_wifi_stopAP(JsVar *jsCallback) {
|
|
// handle the callback parameter
|
|
if (jsCallback != NULL && !jsvIsUndefined(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return;
|
|
}
|
|
|
|
// Change operating mode intelligently. We want to remove us from being
|
|
// an access point but if we are also a station, we want to preserve that.
|
|
esp_err_t err;
|
|
wifi_mode_t mode;
|
|
err = esp_wifi_get_mode(&mode);
|
|
switch(mode) {
|
|
case WIFI_MODE_NULL:
|
|
case WIFI_MODE_STA:
|
|
break;
|
|
case WIFI_MODE_AP:
|
|
mode = WIFI_MODE_NULL;
|
|
break;
|
|
case WIFI_MODE_APSTA:
|
|
mode = WIFI_MODE_STA;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
err = esp_wifi_set_mode(mode);
|
|
if (err != ESP_OK) {
|
|
jsWarn("jswrap_wifi_stopAP: esp_wifi_set_mode rc=%d", err);
|
|
}
|
|
|
|
if (jsvIsFunction(jsCallback)) {
|
|
jsiQueueEvents(NULL, jsCallback, NULL, 0);
|
|
}
|
|
} // End of jswrap_wifi_stopAP
|
|
|
|
void jswrap_wifi_connect(
|
|
JsVar *jsSsid,
|
|
JsVar *jsOptions,
|
|
JsVar *jsCallback
|
|
) {
|
|
|
|
// Check that the ssid value isn't obviously in error.
|
|
if (!jsvIsString(jsSsid)) {
|
|
jsExceptionHere(JSET_ERROR, "No SSID provided");
|
|
return;
|
|
}
|
|
|
|
// Create SSID string
|
|
char ssid[33];
|
|
size_t len = jsvGetString(jsSsid, ssid, sizeof(ssid)-1);
|
|
ssid[len]='\0';
|
|
|
|
// Make sure jsOptions is NULL or an object
|
|
if (jsOptions != NULL && !jsvIsObject(jsOptions)) {
|
|
EXPECT_OPT_EXCEPTION(jsOptions);
|
|
return;
|
|
}
|
|
|
|
// Check callback
|
|
if (g_jsGotIpCallback != NULL) jsvUnLock(g_jsGotIpCallback);
|
|
g_jsGotIpCallback = NULL;
|
|
if (jsCallback != NULL && !jsvIsUndefined(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return;
|
|
}
|
|
|
|
// Clear disconnect callback to prevent disconnection from disabling station mode
|
|
if (g_jsDisconnectCallback != NULL) jsvUnLock(g_jsDisconnectCallback);
|
|
g_jsDisconnectCallback = NULL;
|
|
|
|
// Get the optional password
|
|
char password[65];
|
|
memset(password, 0, sizeof(password));
|
|
if (jsOptions != NULL) {
|
|
JsVar *jsPassword = jsvObjectGetChild(jsOptions, "password", 0);
|
|
if (jsPassword != NULL && !jsvIsString(jsPassword)) {
|
|
jsExceptionHere(JSET_ERROR, "Expecting options.password to be a string but got %t", jsPassword);
|
|
jsvUnLock(jsPassword);
|
|
return;
|
|
}
|
|
if (jsPassword != NULL) {
|
|
size_t len = jsvGetString(jsPassword, password, sizeof(password)-1);
|
|
password[len]='\0';
|
|
} else {
|
|
password[0] = '\0';
|
|
}
|
|
jsvUnLock(jsPassword);
|
|
} // End of we had options
|
|
|
|
// At this point, we have the ssid in "ssid" and the password in "password".
|
|
// Perform an esp_wifi_set_mode
|
|
wifi_mode_t mode;
|
|
esp_err_t err;
|
|
err = esp_wifi_get_mode(&mode);
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_connect: esp_wifi_get_mode: %d", err);
|
|
return;
|
|
}
|
|
switch(mode) {
|
|
case WIFI_MODE_NULL:
|
|
case WIFI_MODE_STA:
|
|
mode = WIFI_MODE_STA;
|
|
break;
|
|
case WIFI_MODE_APSTA:
|
|
case WIFI_MODE_AP:
|
|
mode = WIFI_MODE_APSTA;
|
|
break;
|
|
default:
|
|
jsError( "jswrap_wifi_connect: Unexpected mode type: %d", mode);
|
|
break;
|
|
}
|
|
|
|
err = esp_wifi_set_mode(mode);
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_connect: esp_wifi_set_mode: %d, mode=%d", err, mode);
|
|
return;
|
|
}
|
|
|
|
// Perform a an esp_wifi_set_config
|
|
wifi_config_t staConfig;
|
|
memcpy(staConfig.sta.ssid, ssid, sizeof(staConfig.sta.ssid));
|
|
memcpy(staConfig.sta.password, password, sizeof(staConfig.sta.password));
|
|
staConfig.sta.bssid_set = false;
|
|
esp_wifi_set_auto_connect(false); // turn off default behaviour
|
|
err = esp_wifi_set_config(WIFI_IF_STA, &staConfig);
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_connect: esp_wifi_set_config: %d", err);
|
|
return;
|
|
}
|
|
|
|
// Perform an esp_wifi_start
|
|
err = esp_wifi_start();
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_connect: esp_wifi_start: %d", err);
|
|
return;
|
|
}
|
|
|
|
// Save the callback for later execution.
|
|
g_jsGotIpCallback = jsvLockAgainSafe(jsCallback);
|
|
|
|
// Perform an esp_wifi_connect
|
|
err = esp_wifi_connect();
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_connect: esp_wifi_connect: %d", err);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void jswrap_wifi_scan(JsVar *jsCallback) {
|
|
// If we have a saved scan callback function we must be scanning already
|
|
if (g_jsScanCallback != NULL) {
|
|
jsExceptionHere(JSET_ERROR, "A scan is already in progress.");
|
|
return;
|
|
}
|
|
|
|
// Check and save callback
|
|
if (!jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return;
|
|
}
|
|
g_jsScanCallback = jsvLockAgainSafe(jsCallback);
|
|
|
|
// We need to be in some kind of a station mode in order to perform a scan
|
|
// Now we determine the mode we are currently in and set our new mode appropriately.
|
|
// NULL -> STA
|
|
// STA -> STA
|
|
// AP -> APSTA
|
|
// APSTA -> APSTA
|
|
wifi_mode_t mode;
|
|
esp_err_t err = esp_wifi_get_mode(&mode);
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_scan: esp_wifi_get_mode: %d", err);
|
|
return;
|
|
}
|
|
|
|
switch(mode) {
|
|
case WIFI_MODE_NULL:
|
|
mode = WIFI_MODE_STA;
|
|
break;
|
|
case WIFI_MODE_STA:
|
|
break;
|
|
case WIFI_MODE_AP:
|
|
mode = WIFI_MODE_APSTA;
|
|
break;
|
|
case WIFI_MODE_APSTA:
|
|
break;
|
|
default:
|
|
jsError( "Unknown mode %d", mode);
|
|
break;
|
|
}
|
|
|
|
err = esp_wifi_set_mode(mode);
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_scan: esp_wifi_set_mode: %d", err);
|
|
return;
|
|
}
|
|
|
|
// Perform an esp_wifi_start
|
|
err = esp_wifi_start();
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_connect: esp_wifi_start: %d", err);
|
|
return;
|
|
}
|
|
|
|
wifi_scan_config_t scanConf = {
|
|
.ssid = NULL,
|
|
.bssid = NULL,
|
|
.channel = 0,
|
|
.show_hidden = true
|
|
};
|
|
esp_wifi_scan_start(&scanConf, false); // Don't block for scan.
|
|
// When the scan completes, we will be notified by an arriving event that is handled
|
|
// in the event handler. The event handler will see that we have a callback function
|
|
// registered and will invoke that callback at that time.
|
|
} // End of jswrap_wifi_scan
|
|
|
|
void jswrap_wifi_startAP(
|
|
JsVar *jsSsid, //!< The network SSID that we will use to listen as.
|
|
JsVar *jsOptions, //!< Configuration options.
|
|
JsVar *jsCallback //!< A callback to be invoked when completed.
|
|
) {
|
|
|
|
// Check callback. It is invalid if it is defined and not a function.
|
|
if (jsCallback != NULL && !jsvIsUndefined(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return;
|
|
}
|
|
|
|
// Validate that the SSID value is provided and is a string.
|
|
if (!jsvIsString(jsSsid)) {
|
|
jsExceptionHere(JSET_ERROR, "No SSID.");
|
|
return;
|
|
}
|
|
|
|
// Make sure jsOptions is NULL or an object
|
|
if (jsOptions != NULL && !jsvIsNull(jsOptions) && !jsvIsObject(jsOptions)) {
|
|
EXPECT_OPT_EXCEPTION(jsOptions);
|
|
return;
|
|
}
|
|
|
|
// Check callback
|
|
if (g_jsAPStartedCallback != NULL) jsvUnLock(g_jsAPStartedCallback);
|
|
g_jsAPStartedCallback = NULL;
|
|
if (jsCallback != NULL && !jsvIsUndefined(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return;
|
|
}
|
|
|
|
wifi_ap_config_t apConfig;
|
|
bzero(&apConfig, sizeof(apConfig));
|
|
apConfig.ssid_hidden = 0;
|
|
apConfig.beacon_interval = 100;
|
|
apConfig.channel = 0;
|
|
apConfig.authmode = WIFI_AUTH_OPEN;
|
|
apConfig.max_connection = 4;
|
|
apConfig.ssid_len = (uint8_t)jsvGetString(jsSsid, (char *)apConfig.ssid, sizeof(apConfig.ssid));
|
|
apConfig.authmode = WIFI_AUTH_OPEN;
|
|
strcpy(apConfig.password, "");
|
|
|
|
if (jsvIsObject(jsOptions)) {
|
|
// Handle channel
|
|
JsVar *jsChan = jsvObjectGetChild(jsOptions, "channel", 0);
|
|
if (jsvIsInt(jsChan)) {
|
|
int chan = jsvGetInteger(jsChan);
|
|
if (chan >= 1 && chan <= 13) {
|
|
apConfig.channel = (uint8_t)chan;
|
|
}
|
|
}
|
|
jsvUnLock(jsChan);
|
|
|
|
// Handle password
|
|
JsVar *jsPassword = jsvObjectGetChild(jsOptions, "password", 0);
|
|
if (jsPassword != NULL) {
|
|
if (!jsvIsString(jsPassword) || jsvGetStringLength(jsPassword) < 8) {
|
|
jsExceptionHere(JSET_ERROR, "Password must be string of at least 8 characters");
|
|
jsvUnLock(jsPassword);
|
|
return;
|
|
}
|
|
size_t len = jsvGetString(jsPassword, (char *)apConfig.password, sizeof(apConfig.password)-1);
|
|
apConfig.password[len] = '\0';
|
|
}
|
|
|
|
// Handle the authMode
|
|
JsVar *jsAuth = jsvObjectGetChild(jsOptions, "authMode", 0);
|
|
if (jsvIsString(jsAuth)) {
|
|
if (jsvIsStringEqual(jsAuth, "open")) {
|
|
apConfig.authmode = WIFI_AUTH_OPEN;
|
|
} else if (jsvIsStringEqual(jsAuth, "wpa2")) {
|
|
apConfig.authmode = WIFI_AUTH_WPA2_PSK;
|
|
} else if (jsvIsStringEqual(jsAuth, "wpa")) {
|
|
apConfig.authmode = WIFI_AUTH_WPA_PSK;
|
|
} else if (jsvIsStringEqual(jsAuth, "wpa_wpa2")) {
|
|
apConfig.authmode = WIFI_AUTH_WPA_WPA2_PSK;
|
|
} else {
|
|
jsvUnLock(jsAuth);
|
|
jsExceptionHere(JSET_ERROR, "Unknown authMode value.");
|
|
return;
|
|
}
|
|
} else {
|
|
// no explicit auth mode, set according to presence of password
|
|
if (strlen(apConfig.password) == 0) {
|
|
apConfig.authmode = WIFI_AUTH_OPEN;
|
|
} else {
|
|
apConfig.authmode = WIFI_AUTH_WPA2_PSK;
|
|
}
|
|
} // End of no explicit authMode
|
|
|
|
jsvUnLock(jsAuth);
|
|
|
|
// Make sure password and authMode match
|
|
if (apConfig.authmode != WIFI_AUTH_OPEN && strlen(apConfig.password) == 0) {
|
|
jsExceptionHere(JSET_ERROR, "Password not set but authMode not open.");
|
|
return;
|
|
}
|
|
|
|
// Make sure that if authmode is explicitly open then there is NO password supplied.
|
|
if (apConfig.authmode == WIFI_AUTH_OPEN && strlen(apConfig.password) > 0) {
|
|
jsExceptionHere(JSET_ERROR, "Auth mode set to open but password supplied.");
|
|
return;
|
|
}
|
|
} // End we have an options structure
|
|
|
|
// Set the mode to be accesss point
|
|
// FIX ... we can't hard code this to be just an access point.
|
|
esp_err_t err;
|
|
|
|
// set callback
|
|
if (jsvIsFunction(jsCallback)) {
|
|
g_jsAPStartedCallback = jsvLockAgainSafe(jsCallback);
|
|
}
|
|
|
|
err = esp_wifi_set_mode(WIFI_MODE_AP);
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_startAP: esp_wifi_set_mode: %d", err);
|
|
return;
|
|
}
|
|
|
|
err = esp_wifi_set_config(WIFI_IF_AP, (wifi_config_t *)&apConfig);
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_startAP: wifi_set_config: %d - ssid=%.*s, password=%s, authMode=%d, maxConnections=%d, beacon=%d, channel=%d",
|
|
err, apConfig.ssid_len, apConfig.ssid, apConfig.password, apConfig.authmode, apConfig.max_connection, apConfig.beacon_interval, apConfig.channel);
|
|
return;
|
|
}
|
|
|
|
// Perform an esp_wifi_start
|
|
err = esp_wifi_start();
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_startAP: esp_wifi_start: %d", err);
|
|
return;
|
|
}
|
|
} // End of jswrap_wifi_startAP
|
|
|
|
|
|
JsVar *jswrap_wifi_getStatus(JsVar *jsCallback) {
|
|
UNUSED(jsCallback);
|
|
// We have to determine the following information:
|
|
//
|
|
// - [ ] The status of the station interface
|
|
// - [ ] The status of the access point interface
|
|
// - [done] The current mode of operation
|
|
// - [ ] The physical modulation
|
|
// - [done] The power save type
|
|
// - [ ] The save mode
|
|
//
|
|
// For the status of the station and access point interfaces, we don't know how to get those
|
|
// but have asked here: http://esp32.com/viewtopic.php?f=13&t=330
|
|
|
|
// Get the current mode of operation.
|
|
wifi_mode_t mode;
|
|
esp_wifi_get_mode(&mode);
|
|
|
|
char *modeStr;
|
|
switch(mode) {
|
|
case WIFI_MODE_NULL:
|
|
modeStr = "off";
|
|
break;
|
|
case WIFI_MODE_AP:
|
|
modeStr = "ap";
|
|
break;
|
|
case WIFI_MODE_STA:
|
|
modeStr = "sta";
|
|
break;
|
|
case WIFI_MODE_APSTA:
|
|
modeStr ="sta+ap";
|
|
break;
|
|
default:
|
|
modeStr = "unknown";
|
|
break;
|
|
}
|
|
|
|
// Get the current power save type
|
|
wifi_ps_type_t psType;
|
|
esp_wifi_get_ps(&psType);
|
|
char *psTypeStr;
|
|
switch(psType) {
|
|
case WIFI_PS_MODEM:
|
|
psTypeStr = "modem";
|
|
break;
|
|
case WIFI_PS_NONE:
|
|
psTypeStr = "none";
|
|
break;
|
|
default:
|
|
psTypeStr = "unknown";
|
|
break;
|
|
}
|
|
|
|
JsVar *jsWiFiStatus = jsvNewObject();
|
|
if (g_isStaConnected) {
|
|
jsvObjectSetChildAndUnLock(jsWiFiStatus, "station", jsvNewFromString("connected"));
|
|
} else {
|
|
jsvObjectSetChildAndUnLock(jsWiFiStatus, "station",
|
|
jsvNewFromString(wifiReasonToString(g_lastEventStaDisconnected.reason)));
|
|
}
|
|
jsvObjectSetChildAndUnLock(jsWiFiStatus, "mode", jsvNewFromString(modeStr));
|
|
jsvObjectSetChildAndUnLock(jsWiFiStatus, "powersave", jsvNewFromString(psTypeStr));
|
|
return jsWiFiStatus;
|
|
} // End of jswrap_wifi_getStatus
|
|
|
|
|
|
|
|
void jswrap_wifi_setConfig(JsVar *jsSettings) {
|
|
UNUSED(jsSettings);
|
|
jsError( "jswrap_wifi_setConfig - Not implemented");
|
|
} // End of jswrap_wifi_setConfig
|
|
|
|
|
|
JsVar *jswrap_wifi_getDetails(JsVar *jsCallback) {
|
|
// Check callback
|
|
if (jsCallback != NULL && !jsvIsNull(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return NULL;
|
|
}
|
|
|
|
JsVar *jsDetails = jsvNewObject();
|
|
if (g_isStaConnected == true) {
|
|
wifi_sta_config_t config;
|
|
esp_wifi_get_config(WIFI_IF_STA, (wifi_config_t *)&config);
|
|
char buf[65];
|
|
|
|
// ssid
|
|
strncpy(buf, (char *)config.ssid, 32);
|
|
buf[32] = 0;
|
|
jsvObjectSetChildAndUnLock(jsDetails, "ssid", jsvNewFromString(buf));
|
|
|
|
// password
|
|
strncpy(buf, (char *)config.password, 64);
|
|
buf[64] = 0;
|
|
jsvObjectSetChildAndUnLock(jsDetails, "password", jsvNewFromString((char *)config.password));
|
|
|
|
// Status
|
|
jsvObjectSetChildAndUnLock(jsDetails, "status", jsvNewFromString("connected"));
|
|
|
|
// Authmode
|
|
jsvObjectSetChildAndUnLock(jsDetails, "authMode",
|
|
jsvNewFromString(authModeToString(g_lastEventStaConnected.authmode)));
|
|
} else {
|
|
// Status
|
|
jsvObjectSetChildAndUnLock(jsDetails, "status",
|
|
jsvNewFromString(wifiReasonToString(g_lastEventStaDisconnected.reason)));
|
|
}
|
|
|
|
// Schedule callback if a function was provided
|
|
if (jsvIsFunction(jsCallback)) {
|
|
JsVar *params[1];
|
|
params[0] = jsDetails;
|
|
jsiQueueEvents(NULL, jsCallback, params, 1);
|
|
}
|
|
return jsDetails;
|
|
} // End of jswrap_wifi_getDetails
|
|
|
|
|
|
JsVar *jswrap_wifi_getAPDetails(JsVar *jsCallback) {
|
|
// Check callback
|
|
if (jsCallback != NULL && !jsvIsNull(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return NULL;
|
|
}
|
|
|
|
JsVar *jsDetails = jsvNewObject();
|
|
|
|
wifi_ap_config_t config;
|
|
esp_wifi_get_config(WIFI_IF_AP, (wifi_config_t *)&config);
|
|
jsvObjectSetChildAndUnLock(jsDetails, "authMode", jsvNewFromString(authModeToString(config.authmode)));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "hidden", jsvNewFromBool(config.ssid_hidden));
|
|
jsvObjectSetChildAndUnLock(jsDetails, "maxConn", jsvNewFromInteger(config.max_connection));
|
|
|
|
char buf[65];
|
|
|
|
// ssid
|
|
strncpy(buf, (char *)config.ssid, 32);
|
|
buf[32] = 0;
|
|
jsvObjectSetChildAndUnLock(jsDetails, "ssid", jsvNewFromString(buf));
|
|
|
|
// password
|
|
strncpy(buf, (char *)config.password, 64);
|
|
buf[64] = 0;
|
|
jsvObjectSetChildAndUnLock(jsDetails, "password", jsvNewFromString((char *)config.password));
|
|
|
|
// Schedule callback if a function was provided
|
|
if (jsvIsFunction(jsCallback)) {
|
|
JsVar *params[1];
|
|
params[0] = jsDetails;
|
|
jsiQueueEvents(NULL, jsCallback, params, 1);
|
|
}
|
|
return jsDetails;
|
|
} // End of jswrap_wifi_getAPDetails
|
|
|
|
|
|
void jswrap_wifi_save(JsVar *what) {
|
|
if (jsvIsString(what) && jsvIsStringEqual(what, "clear")) {
|
|
esp_wifi_set_auto_connect(false);
|
|
} else {
|
|
esp_wifi_set_auto_connect(true);
|
|
}
|
|
} // End of jswrap_wifi_save
|
|
|
|
|
|
void jswrap_wifi_restore(void) {
|
|
bool auto_connect;
|
|
int err=esp_wifi_get_auto_connect(&auto_connect);
|
|
|
|
if ( auto_connect ) {
|
|
err = esp_wifi_start();
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_restore: esp_wifi_start: %d", err);
|
|
}
|
|
|
|
wifi_mode_t mode;
|
|
err = esp_wifi_get_mode(&mode);
|
|
if ( ( mode == WIFI_MODE_STA ) || ( mode == WIFI_MODE_APSTA ) ) {
|
|
// Perform an esp_wifi_start
|
|
err = esp_wifi_connect();
|
|
if (err != ESP_OK) {
|
|
jsError( "jswrap_wifi_restore: esp_wifi_connect: %d", err - ESP_ERR_WIFI_BASE);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
// No previous wifi.save()
|
|
}
|
|
|
|
} // End of jswrap_wifi_restore
|
|
|
|
|
|
/**
|
|
* Get the ip info for the given interface. The interfaces are:
|
|
* * TCPIP_ADAPTER_IF_STA - Station
|
|
* * TCPIP_ADAPTER_IF_AP - Access Point
|
|
*/
|
|
static JsVar *getIPInfo(JsVar *jsCallback, tcpip_adapter_if_t interface) {
|
|
// Check callback
|
|
if (jsCallback != NULL && !jsvIsNull(jsCallback) && !jsvIsFunction(jsCallback)) {
|
|
EXPECT_CB_EXCEPTION(jsCallback);
|
|
return NULL;
|
|
}
|
|
|
|
// first get IP address info, this may fail if we're not connected
|
|
tcpip_adapter_ip_info_t ipInfo;
|
|
esp_err_t err = tcpip_adapter_get_ip_info(interface, &ipInfo);
|
|
JsVar *jsIpInfo = jsvNewObject();
|
|
if (err == ESP_OK) {
|
|
jsvObjectSetChildAndUnLock(jsIpInfo, "ip",
|
|
networkGetAddressAsString((uint8_t *)&ipInfo.ip, 4, 10, '.'));
|
|
jsvObjectSetChildAndUnLock(jsIpInfo, "netmask",
|
|
networkGetAddressAsString((uint8_t *)&ipInfo.netmask, 4, 10, '.'));
|
|
jsvObjectSetChildAndUnLock(jsIpInfo, "gw",
|
|
networkGetAddressAsString((uint8_t *)&ipInfo.gw, 4, 10, '.'));
|
|
}
|
|
|
|
// now get MAC address (which always succeeds)
|
|
uint8_t macAddr[6];
|
|
esp_wifi_get_mac(interface==TCPIP_ADAPTER_IF_STA?WIFI_IF_STA:WIFI_IF_AP, macAddr);
|
|
char macAddrString[6*3 + 1];
|
|
sprintf(macAddrString, MACSTR, MAC2STR(macAddr));
|
|
jsvObjectSetChildAndUnLock(jsIpInfo, "mac", jsvNewFromString(macAddrString));
|
|
|
|
// Schedule callback if a function was provided
|
|
if (jsvIsFunction(jsCallback)) {
|
|
JsVar *params[1];
|
|
params[0] = jsIpInfo;
|
|
jsiQueueEvents(NULL, jsCallback, params, 1);
|
|
}
|
|
|
|
return jsIpInfo;
|
|
} // End of getIPInfo
|
|
|
|
|
|
JsVar *jswrap_wifi_getIP(JsVar *jsCallback) {
|
|
JsVar *jsIpInfo = getIPInfo(jsCallback, TCPIP_ADAPTER_IF_STA);
|
|
return jsIpInfo;
|
|
} // End of jswrap_wifi_getIP
|
|
|
|
|
|
JsVar *jswrap_wifi_getAPIP(JsVar *jsCallback) {
|
|
JsVar *jsIpInfo = getIPInfo(jsCallback, TCPIP_ADAPTER_IF_AP);
|
|
return jsIpInfo;
|
|
}
|
|
|
|
void jswrap_wifi_getHostByName(
|
|
JsVar *jsHostname,
|
|
JsVar *jsCallback
|
|
) {
|
|
UNUSED(jsHostname);
|
|
UNUSED(jsCallback);
|
|
jsError( "jswrap_wifi_getHostByName - Not implemented - no api in esp-idf");
|
|
// Could use net_esp32_gethostbyname in network_esp32.c
|
|
}
|
|
|
|
JsVar *jswrap_wifi_getHostname(JsVar *jsCallback) {
|
|
UNUSED(jsCallback);
|
|
jsError( "jswrap_wifi_getHostname - Not implemented");
|
|
return NULL;
|
|
}
|
|
|
|
void jswrap_wifi_setHostname(
|
|
JsVar *jsHostname //!< The hostname to set for device.
|
|
) {
|
|
UNUSED(jsHostname);
|
|
jsError( "jswrap_wifi_setHostname - Not implemented");
|
|
}
|
|
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "ESP32",
|
|
"name" : "ping",
|
|
"generate" : "jswrap_ESP32_ping",
|
|
"params" : [
|
|
["ipAddr", "JsVar", "A string representation of an IP address."],
|
|
["pingCallback", "JsVar", "Optional callback function."]
|
|
]
|
|
}
|
|
Perform a network ping request. The parameter can be either a String or a numeric IP address.
|
|
**Note:** This function should probably be removed, or should it be part of the wifi library?
|
|
*/
|
|
void jswrap_ESP32_ping(
|
|
JsVar *ipAddr, //!< A string or integer representation of an IP address.
|
|
JsVar *pingCallback //!< Optional callback function.
|
|
) {
|
|
UNUSED(ipAddr);
|
|
UNUSED(pingCallback);
|
|
jsError( "jswrap_ESP32_ping - Not implemented");
|
|
}
|