esp32: move helper code into lws
This commit is contained in:
parent
906f137794
commit
839b1af4e4
8 changed files with 927 additions and 2 deletions
|
@ -598,7 +598,8 @@ else()
|
||||||
else()
|
else()
|
||||||
if (LWS_WITH_ESP32)
|
if (LWS_WITH_ESP32)
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
lib/lws-plat-esp32.c)
|
lib/lws-plat-esp32.c
|
||||||
|
lib/romfs.c)
|
||||||
else()
|
else()
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
lib/lws-plat-unix.c)
|
lib/lws-plat-unix.c)
|
||||||
|
|
|
@ -17,6 +17,7 @@ build:
|
||||||
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS)" \
|
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS)" \
|
||||||
-DCROSS_PATH=$(CROSS_PATH) \
|
-DCROSS_PATH=$(CROSS_PATH) \
|
||||||
-DCOMPONENT_PATH=$(COMPONENT_PATH) \
|
-DCOMPONENT_PATH=$(COMPONENT_PATH) \
|
||||||
|
-DBUILD_DIR_BASE=$(BUILD_DIR_BASE) \
|
||||||
-DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/cross-esp32.cmake \
|
-DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/cross-esp32.cmake \
|
||||||
-DCMAKE_BUILD_TYPE=RELEASE \
|
-DCMAKE_BUILD_TYPE=RELEASE \
|
||||||
-DLWS_WITH_NO_LOGS=0 \
|
-DLWS_WITH_NO_LOGS=0 \
|
||||||
|
|
|
@ -12,7 +12,7 @@ set(CMAKE_SYSTEM_NAME Linux)
|
||||||
# Name of C compiler.
|
# Name of C compiler.
|
||||||
set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/xtensa-esp32-elf-gcc")
|
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)
|
# Where to look for the target environment. (More paths can be added here)
|
||||||
set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
|
set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
|
||||||
|
|
|
@ -460,6 +460,16 @@ struct pollfd {
|
||||||
#define POLLHUP 0x0010
|
#define POLLHUP 0x0010
|
||||||
#define POLLNVAL 0x0020
|
#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"
|
#include "freertos/timers.h"
|
||||||
|
|
||||||
#if !defined(CONFIG_FREERTOS_HZ)
|
#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);
|
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
|
#else
|
||||||
typedef int lws_sockfd_type;
|
typedef int lws_sockfd_type;
|
||||||
|
|
|
@ -528,3 +528,277 @@ char *ERR_error_string(unsigned long e, char *buf)
|
||||||
|
|
||||||
return "unknown";
|
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
216
lib/romfs.c
Normal 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
63
lib/romfs.h
Normal 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);
|
||||||
|
|
333
plugins/protocol_esp32_lws_scan.c
Normal file
333
plugins/protocol_esp32_lws_scan.c
Normal 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 \
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue