1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

esp32: move helper code into lws

This commit is contained in:
Andy Green 2017-03-10 14:29:21 +08:00
parent 4198c20920
commit e0572d3bef
8 changed files with 927 additions and 2 deletions

View file

@ -598,7 +598,8 @@ else()
else()
if (LWS_WITH_ESP32)
list(APPEND SOURCES
lib/lws-plat-esp32.c)
lib/lws-plat-esp32.c
lib/romfs.c)
else()
list(APPEND SOURCES
lib/lws-plat-unix.c)

View file

@ -17,6 +17,7 @@ build:
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS)" \
-DCROSS_PATH=$(CROSS_PATH) \
-DCOMPONENT_PATH=$(COMPONENT_PATH) \
-DBUILD_DIR_BASE=$(BUILD_DIR_BASE) \
-DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/cross-esp32.cmake \
-DCMAKE_BUILD_TYPE=RELEASE \
-DLWS_WITH_NO_LOGS=0 \

View file

@ -12,7 +12,7 @@ set(CMAKE_SYSTEM_NAME Linux)
# Name of C compiler.
set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/xtensa-esp32-elf-gcc")
SET(CMAKE_C_FLAGS "-nostdlib -Wall -Werror -I${COMPONENT_PATH}/../lwip/include/lwip/posix -I${COMPONENT_PATH}/../lwip/include/lwip -I${COMPONENT_PATH}/../lwip/include/lwip/port -I${COMPONENT_PATH}/../esp32/include/ ${LWS_C_FLAGS} -I${COMPONENT_PATH}/../nvs_flash/test_nvs_host -I${COMPONENT_PATH}/../freertos/include -Os" CACHE STRING "" FORCE)
SET(CMAKE_C_FLAGS "-nostdlib -Wall -Werror -I${BUILD_DIR_BASE}/include -I${COMPONENT_PATH}/../driver/include -I${COMPONENT_PATH}/../spi_flash/include -I${COMPONENT_PATH}/../nvs_flash/include -I${COMPONENT_PATH}/../tcpip_adapter/include -I${COMPONENT_PATH}/../lwip/include/lwip/posix -I${COMPONENT_PATH}/../lwip/include/lwip -I${COMPONENT_PATH}/../lwip/include/lwip/port -I${COMPONENT_PATH}/../esp32/include/ ${LWS_C_FLAGS} -I${COMPONENT_PATH}/../nvs_flash/test_nvs_host -I${COMPONENT_PATH}/../freertos/include -Os" CACHE STRING "" FORCE)
# Where to look for the target environment. (More paths can be added here)
set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")

View file

@ -460,6 +460,16 @@ struct pollfd {
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "nvs.h"
#include "driver/gpio.h"
#include "esp_spi_flash.h"
#include "freertos/timers.h"
#if !defined(CONFIG_FREERTOS_HZ)
@ -513,8 +523,35 @@ static inline void uv_close(uv_handle_t *h, void *v)
xTimerDelete(*(uv_timer_t *)h, 0);
}
/* ESP32 helper declarations */
#define LWS_PLUGIN_STATIC
/* user code provides these */
extern char lws_esp32_model[16];
extern int
lws_esp32_is_booting_in_ap_mode(void);
extern void
lws_esp32_identify_physical_device(void);
/* lws-plat-esp32 provides these */
extern void (*lws_cb_scan_done)(void *);
extern void *lws_cb_scan_done_arg;
extern char lws_esp32_serial[], lws_esp32_force_ap, lws_esp32_region;
extern esp_err_t
lws_esp32_event_passthru(void *ctx, system_event_t *event);
extern void
lws_esp32_wlan_config(void);
extern void
lws_esp32_wlan_start(void);
struct lws_context_creation_info;
extern struct lws_context *
lws_esp32_init(struct lws_context_creation_info *, unsigned int _romfs);
#else
typedef int lws_sockfd_type;

View file

@ -528,3 +528,277 @@ char *ERR_error_string(unsigned long e, char *buf)
return "unknown";
}
/* helper functionality */
#include "romfs.h"
void (*lws_cb_scan_done)(void *);
void *lws_cb_scan_done_arg;
char lws_esp32_serial[16] = "unknown", lws_esp32_force_ap = 0,
lws_esp32_region = WIFI_COUNTRY_US; // default to safest option
static romfs_t lws_esp32_romfs;
/*
* configuration related to the AP setup website
*
* The 'esplws-scan' protocol drives the configuration
* site, and updates the scan results in realtime over
* a websocket link.
*/
#include "../plugins/protocol_esp32_lws_scan.c"
static const struct lws_protocols protocols_ap[] = {
{
"http-only",
lws_callback_http_dummy,
0, /* per_session_data_size */
900, 0, NULL
},
LWS_PLUGIN_PROTOCOL_ESPLWS_SCAN,
{ NULL, NULL, 0, 0, 0, NULL } /* terminator */
};
static const struct lws_protocol_vhost_options ap_pvo = {
NULL,
NULL,
"esplws-scan",
""
};
static const struct lws_http_mount mount_ap = {
.mountpoint = "/",
.origin = "/ap",
.def = "index.html",
.origin_protocol = LWSMPRO_FILE,
.mountpoint_len = 1,
};
struct esp32_file {
const struct inode *i;
};
esp_err_t lws_esp32_event_passthru(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_SCAN_DONE:
if (lws_cb_scan_done)
lws_cb_scan_done(lws_cb_scan_done_arg);
break;
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
break;
default:
break;
}
return ESP_OK;
}
static lws_fop_fd_t IRAM_ATTR
esp32_lws_fops_open(const struct lws_plat_file_ops *fops, const char *filename,
const char *vfs_path, lws_fop_flags_t *flags)
{
struct esp32_file *f = malloc(sizeof(*f));
lws_fop_fd_t fop_fd;
size_t len;
lwsl_notice("%s: %s\n", __func__, filename);
if (!f)
return NULL;
f->i = romfs_get_info(lws_esp32_romfs, filename, &len);
if (!f->i)
goto bail;
fop_fd = malloc(sizeof(*fop_fd));
if (!fop_fd)
goto bail;
fop_fd->fops = fops;
fop_fd->filesystem_priv = f;
fop_fd->flags = *flags;
fop_fd->len = len;
fop_fd->pos = 0;
return fop_fd;
bail:
free(f);
return NULL;
}
static int IRAM_ATTR
esp32_lws_fops_close(lws_fop_fd_t *fop_fd)
{
free((*fop_fd)->filesystem_priv);
free(*fop_fd);
*fop_fd = NULL;
return 0;
}
static lws_fileofs_t IRAM_ATTR
esp32_lws_fops_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset_from_cur_pos)
{
fop_fd->pos += offset_from_cur_pos;
if (fop_fd->pos > fop_fd->len)
fop_fd->pos = fop_fd->len;
return 0;
}
static int IRAM_ATTR
esp32_lws_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount, uint8_t *buf,
lws_filepos_t len)
{
struct esp32_file *f = fop_fd->filesystem_priv;
if ((long)buf & 3) {
lwsl_err("misaligned buf\n");
return -1;
}
if (fop_fd->pos >= fop_fd->len)
return 0;
if (len > fop_fd->len - fop_fd->pos)
len = fop_fd->len - fop_fd->pos;
spi_flash_read((uint32_t)(char *)f->i + fop_fd->pos, buf, len);
*amount = len;
fop_fd->pos += len;
return 0;
}
static const struct lws_plat_file_ops fops = {
.LWS_FOP_OPEN = esp32_lws_fops_open,
.LWS_FOP_CLOSE = esp32_lws_fops_close,
.LWS_FOP_READ = esp32_lws_fops_read,
.LWS_FOP_SEEK_CUR = esp32_lws_fops_seek_cur,
};
static wifi_config_t sta_config = {
.sta = {
.bssid_set = false
}
}, ap_config = {
.ap = {
.channel = 6,
.authmode = WIFI_AUTH_OPEN,
.max_connection = 1,
}
};
void
lws_esp32_wlan_config(void)
{
nvs_handle nvh;
char r[2];
size_t s;
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
s = sizeof(sta_config.sta.ssid) - 1;
if (nvs_get_str(nvh, "ssid", (char *)sta_config.sta.ssid, &s) != ESP_OK)
lws_esp32_force_ap = 1;
s = sizeof(sta_config.sta.password) - 1;
if (nvs_get_str(nvh, "password", (char *)sta_config.sta.password, &s) != ESP_OK)
lws_esp32_force_ap = 1;
s = sizeof(lws_esp32_serial) - 1;
if (nvs_get_str(nvh, "serial", lws_esp32_serial, &s) != ESP_OK)
lws_esp32_force_ap = 1;
else
snprintf((char *)ap_config.ap.ssid, sizeof(ap_config.ap.ssid) - 1,
"config-%s-%s", lws_esp32_model, lws_esp32_serial);
s = sizeof(r);
if (nvs_get_str(nvh, "region", r, &s) != ESP_OK)
lws_esp32_force_ap = 1;
else
lws_esp32_region = atoi(r);
nvs_close(nvh);
tcpip_adapter_init();
}
void
lws_esp32_wlan_start(void)
{
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_RAM));
ESP_ERROR_CHECK( esp_wifi_set_country(lws_esp32_region));
if (!lws_esp32_is_booting_in_ap_mode() && !lws_esp32_force_ap) {
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
} else {
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_APSTA) );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_AP, &ap_config) );
}
ESP_ERROR_CHECK( esp_wifi_start());
tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, (const char *)&ap_config.ap.ssid[7]);
if (!lws_esp32_is_booting_in_ap_mode() && !lws_esp32_force_ap)
ESP_ERROR_CHECK( esp_wifi_connect());
}
struct lws_context *
lws_esp32_init(struct lws_context_creation_info *info, unsigned int _romfs)
{
size_t romfs_size;
struct lws_context *context;
lws_set_log_level(65535, lwsl_emit_syslog);
context = lws_create_context(info);
if (context == NULL) {
lwsl_err("Failed to create context\n");
return NULL;
}
lws_esp32_romfs = (romfs_t)(void *)_romfs;
romfs_size = romfs_mount_check(lws_esp32_romfs);
if (!romfs_size) {
lwsl_err("Failed to mount ROMFS\n");
return NULL;
}
lwsl_notice("ROMFS length %uKiB\n", romfs_size >> 10);
/* set the lws vfs to use our romfs */
lws_set_fops(context, &fops);
if (lws_esp32_is_booting_in_ap_mode() || lws_esp32_force_ap) {
info->vhost_name = "ap";
info->protocols = protocols_ap;
info->mounts = &mount_ap;
info->pvo = &ap_pvo;
}
if (!lws_create_vhost(context, info))
lwsl_err("Failed to create vhost\n");
lws_protocol_init(context);
return context;
}

216
lib/romfs.c Normal file
View file

@ -0,0 +1,216 @@
/*
* Copyright (C) 2017 National Institute of Advanced Industrial Science
* and Technology (AIST)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of AIST nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "romfs.h"
#include "esp_spi_flash.h"
#define RFS_STRING_MAX 64
static u32_be_t cache[(RFS_STRING_MAX + 32) / 4];
static romfs_inode_t ci = (romfs_inode_t)cache;
static romfs_t cr = (romfs_t)cache;
static void
set_cache(romfs_inode_t inode, size_t len)
{
spi_flash_read((uint32_t)inode, cache, len);
}
static uint32_t
ntohl(const u32_be_t be)
{
return ((be >> 24) & 0xff) |
((be >> 16) & 0xff) << 8 |
((be >> 8) & 0xff) << 16 |
(be & 0xff) << 24;
}
static romfs_inode_t
romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path);
static int
plus_padding(const uint8_t *s)
{
int n;
set_cache((romfs_inode_t)s, RFS_STRING_MAX);
n = strlen((const char *)cache);
if (!(n & 15))
n += 0x10;
return (n + 15) & ~15;
}
static romfs_inode_t
skip_and_pad(romfs_inode_t ri)
{
const uint8_t *p = ((const uint8_t *)ri) + sizeof(*ri);
return (romfs_inode_t)(p + plus_padding(p));
}
size_t
romfs_mount_check(romfs_t romfs)
{
set_cache((romfs_inode_t)romfs, sizeof(*romfs));
if (cr->magic1 != 0x6d6f722d ||
cr->magic2 != 0x2d736631)
return 0;
return ntohl(cr->size);
}
static romfs_inode_t
romfs_symlink(romfs_t romfs, romfs_inode_t level, romfs_inode_t i)
{
const char *p = (const char *)skip_and_pad(i);
if (*p == '/') {
level = skip_and_pad((romfs_inode_t)romfs);
p++;
}
return romfs_lookup(romfs, level, p);
}
static romfs_inode_t
dir_link(romfs_t romfs, romfs_inode_t i)
{
set_cache(i, sizeof(*i));
return (romfs_inode_t)((const uint8_t *)romfs +
ntohl(ci->dir_start));
}
static romfs_inode_t
romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
{
romfs_inode_t level, i = start;
const char *p, *n, *cp;
uint32_t next_be;
if (start == (romfs_inode_t)romfs)
i = skip_and_pad((romfs_inode_t)romfs);
level = i;
while (i != (romfs_inode_t)romfs) {
p = path;
n = ((const char *)i) + sizeof(*i);
set_cache(i, sizeof(*i));
next_be = ci->next;
cp = (const char *)cache;
set_cache((romfs_inode_t)n, RFS_STRING_MAX);
while (*p && *p != '/' && *cp && *p == *cp) {
p++;
n++;
cp++;
}
if (!*cp && (!*p || *p == '/') &&
(ntohl(next_be) & 7) == RFST_HARDLINK) {
set_cache(i, sizeof(*i));
return (romfs_inode_t)
((const uint8_t *)romfs +
(ntohl(ci->dir_start) & ~15));
}
if (!*p && !*cp) {
set_cache(i, sizeof(*i));
if ((ntohl(ci->next) & 7) == RFST_SYMLINK) {
i = romfs_symlink(romfs, level, i);
continue;
}
return i;
}
if (*p == '/' && !*cp) {
set_cache(i, sizeof(*i));
switch (ntohl(ci->next) & 7) {
case RFST_SYMLINK:
i = romfs_symlink(romfs, level, i);
if (!i)
return NULL;
i = dir_link(romfs, i);
while (*path != '/' && *path)
path++;
if (!*path)
return NULL;
path++;
continue;
case RFST_DIR:
path = p + 1;
i = dir_link(romfs, i);
break;
default:
path = p + 1;
i = skip_and_pad(i);
break;
}
level = i;
continue;
}
set_cache(i, sizeof(*i));
if (!(ntohl(ci->next) & ~15))
return NULL;
i = (romfs_inode_t)((const uint8_t *)romfs +
(ntohl(ci->next) & ~15));
}
return NULL;
}
const void *
romfs_get_info(romfs_t romfs, const char *path, size_t *len)
{
romfs_inode_t i;
if (*path == '/')
path++;
i = romfs_lookup(romfs, (romfs_inode_t)romfs, path);
if (!i)
return NULL;
set_cache(i, sizeof(*i));
*len = ntohl(ci->size);
return (void *)skip_and_pad(i);
}

63
lib/romfs.h Normal file
View file

@ -0,0 +1,63 @@
/*
* Copyright (C) 2017 National Institute of Advanced Industrial Science
* and Technology (AIST)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of AIST nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
typedef uint32_t u32_be_t;
struct romfs_superblock {
u32_be_t magic1;
u32_be_t magic2;
u32_be_t size;
u32_be_t checksum;
};
struct romfs_i {
u32_be_t next;
u32_be_t dir_start;
u32_be_t size;
u32_be_t checksum;
};
enum {
RFST_HARDLINK = 0,
RFST_DIR = 1,
RFST_SYMLINK = 3,
};
typedef const struct romfs_i *romfs_inode_t;
typedef const struct romfs_superblock *romfs_t;
const void *
romfs_get_info(romfs_t romfs, const char *path, size_t *len);
size_t
romfs_mount_check(romfs_t romfs);

View file

@ -0,0 +1,333 @@
/*
* Example ESP32 app code using Libwebsockets
*
* Copyright (C) 2017 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* The person who associated a work with this deed has dedicated
* the work to the public domain by waiving all of his or her rights
* to the work worldwide under copyright law, including all related
* and neighboring rights, to the extent allowed by law. You can copy,
* modify, distribute and perform the work, even for commercial purposes,
* all without asking permission.
*
* The test apps are intended to be adapted for use in your code, which
* may be proprietary. So unlike the library itself, they are licensed
* Public Domain.
*
*/
#include <string.h>
#include <nvs.h>
typedef enum {
SCAN_STATE_NONE,
SCAN_STATE_INITIAL,
SCAN_STATE_LIST,
SCAN_STATE_FINAL
} scan_state;
struct store_json {
const char *j;
const char *nvs;
};
struct per_session_data__esplws_scan {
struct per_session_data__esplws_scan *next;
scan_state scan_state;
char ap_record;
unsigned char subsequent:1;
unsigned char changed_partway:1;
};
struct per_vhost_data__esplws_scan {
wifi_ap_record_t ap_records[20];
TimerHandle_t timer;
struct per_session_data__esplws_scan *live_pss_list;
struct lws_context *context;
struct lws_vhost *vhost;
const struct lws_protocols *protocol;
uint16_t count_ap_records;
char count_live_pss;
unsigned char scan_ongoing:1;
unsigned char completed_any_scan:1;
unsigned char reboot:1;
};
static const struct store_json store_json[] = {
{ "ssid\":\"", "ssid" },
{ ",\"pw\":\"", "password" },
{ ",\"serial\":\"", "serial" },
{ ",\"region\":\"", "region" },
};
static wifi_scan_config_t scan_config = {
.ssid = 0,
.bssid = 0,
.channel = 0,
.show_hidden = true
};
extern void (*lws_cb_scan_done)(void *);
extern void *lws_cb_scan_done_arg;
static void
scan_finished(void *v);
static int
esplws_simple_arg(char *dest, int len, const char *in, const char *match)
{
const char *p = strstr(in, match);
int n = 0;
if (!p) {
lwsl_err("No match %s\n", match);
return 1;
}
p += strlen(match);
while (*p && *p != '\"' && n < len - 1)
dest[n++] = *p++;
dest[n] = '\0';
return 0;
}
static void
scan_start(struct per_vhost_data__esplws_scan *vhd)
{
int n;
if (vhd->reboot)
esp_restart();
if (vhd->scan_ongoing)
return;
vhd->scan_ongoing = 1;
lws_cb_scan_done = scan_finished;
lws_cb_scan_done_arg = vhd;
n = esp_wifi_scan_start(&scan_config, false);
if (n != ESP_OK)
lwsl_err("scan start failed %d\n", n);
}
static void timer_cb(TimerHandle_t t)
{
struct per_vhost_data__esplws_scan *vhd = pvTimerGetTimerID(t);
scan_start(vhd);
}
static void
scan_finished(void *v)
{
struct per_vhost_data__esplws_scan *vhd = v;
struct per_session_data__esplws_scan *p = vhd->live_pss_list;
vhd->scan_ongoing = 0;
vhd->count_ap_records = ARRAY_SIZE(vhd->ap_records);
if (esp_wifi_scan_get_ap_records(&vhd->count_ap_records, vhd->ap_records) != ESP_OK) {
lwsl_err("%s: failed\n", __func__);
return;
}
while (p) {
if (p->scan_state != SCAN_STATE_INITIAL && p->scan_state != SCAN_STATE_NONE)
p->changed_partway = 1;
else
p->scan_state = SCAN_STATE_INITIAL;
p = p->next;
}
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
}
static int
callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__esplws_scan *pss =
(struct per_session_data__esplws_scan *)user;
struct per_vhost_data__esplws_scan *vhd =
(struct per_vhost_data__esplws_scan *)
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
lws_get_protocol(wsi));
char buf[LWS_PRE + 384], /*ip[24],*/ *start = buf + LWS_PRE - 1, *p = start,
*end = buf + sizeof(buf) - 1;
wifi_ap_record_t *r;
int n, m;
switch (reason) {
case LWS_CALLBACK_PROTOCOL_INIT:
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
lws_get_protocol(wsi),
sizeof(struct per_vhost_data__esplws_scan));
vhd->context = lws_get_context(wsi);
vhd->protocol = lws_get_protocol(wsi);
vhd->vhost = lws_get_vhost(wsi);
vhd->timer = xTimerCreate("x", pdMS_TO_TICKS(10000), 1, vhd,
(TimerCallbackFunction_t)timer_cb);
xTimerStart(vhd->timer, 0);
vhd->scan_ongoing = 0;
scan_start(vhd);
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
if (!vhd)
break;
xTimerStop(vhd->timer, 0);
xTimerDelete(vhd->timer, 0);
break;
case LWS_CALLBACK_ESTABLISHED:
vhd->count_live_pss++;
pss->next = vhd->live_pss_list;
vhd->live_pss_list = pss;
/* if we have scan results, update them. Otherwise wait */
if (vhd->count_ap_records) {
pss->scan_state = SCAN_STATE_INITIAL;
lws_callback_on_writable(wsi);
}
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
switch (pss->scan_state) {
case SCAN_STATE_INITIAL:
n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;;
p += snprintf(p, end - p,
"{ \"model\":\"%s\","
" \"serial\":\"%s\","
" \"host\":\"%s-%s\","
" \"region\":\"%d\","
" \"aps\":[",
lws_esp32_model,
lws_esp32_serial,
lws_esp32_model, lws_esp32_serial,
lws_esp32_region);
pss->scan_state = SCAN_STATE_LIST;
pss->ap_record = 0;
pss->subsequent = 0;
break;
case SCAN_STATE_LIST:
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
if (pss->ap_record >= vhd->count_ap_records)
goto scan_state_final;
if (pss->subsequent)
*p++ = ',';
pss->subsequent = 1;
r = &vhd->ap_records[(int)pss->ap_record++];
p += snprintf(p, end - p,
"{\"ssid\":\"%s\","
"\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\","
"\"rssi\":\"%d\","
"\"chan\":\"%d\","
"\"auth\":\"%d\"}",
r->ssid,
r->bssid[0], r->bssid[1], r->bssid[2],
r->bssid[3], r->bssid[4], r->bssid[5],
r->rssi, r->primary, r->authmode);
if (pss->ap_record >= vhd->count_ap_records)
pss->scan_state = SCAN_STATE_FINAL;
break;
case SCAN_STATE_FINAL:
scan_state_final:
n = LWS_WRITE_CONTINUATION;
p += sprintf(p, "]}");
if (pss->changed_partway) {
pss->subsequent = 0;
pss->scan_state = SCAN_STATE_INITIAL;
} else
pss->scan_state = SCAN_STATE_NONE;
break;
default:
return 0;
}
m = lws_write(wsi, (unsigned char *)start, p - start, n);
if (m < 0) {
lwsl_err("ERROR %d writing to di socket\n", m);
return -1;
}
if (pss->scan_state != SCAN_STATE_NONE)
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_RECEIVE:
{
nvs_handle nvh;
char p[64];
int n;
if (strstr((const char *)in, "identify")) {
lws_esp32_identify_physical_device();
break;
}
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
lwsl_err("Unable to open nvs\n");
break;
}
for (n = 0; n < ARRAY_SIZE(store_json); n++) {
if (esplws_simple_arg(p, sizeof(p), in, store_json[n].j))
goto bail_nvs;
if (nvs_set_str(nvh, store_json[n].nvs, p) != ESP_OK) {
lwsl_err("Unable to store %s in nvm\n", store_json[n].nvs);
goto bail_nvs;
}
}
nvs_commit(nvh);
nvs_close(nvh);
vhd->reboot = 1;
break;
bail_nvs:
nvs_close(nvh);
return 1;
}
case LWS_CALLBACK_CLOSED:
{
struct per_session_data__esplws_scan **p = &vhd->live_pss_list;
while (*p) {
if ((*p) == pss) {
*p = pss->next;
continue;
}
p = &((*p)->next);
}
vhd->count_live_pss--;
}
break;
default:
break;
}
return 0;
}
#define LWS_PLUGIN_PROTOCOL_ESPLWS_SCAN \
{ \
"esplws-scan", \
callback_esplws_scan, \
sizeof(struct per_session_data__esplws_scan), \
512, 0, NULL \
}