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:
parent
4198c20920
commit
e0572d3bef
8 changed files with 927 additions and 2 deletions
|
@ -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)
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
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