blob: b6b29636b5ed19d10e70e0409d6dc9775fc8cd49 [file] [log] [blame]
/*
* ESP32 Scan / Factory protocol handler
*
* Copyright (C) 2017 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA*
*
*/
#include <string.h>
#include <nvs.h>
#include <esp_ota_ops.h>
typedef enum {
SCAN_STATE_NONE,
SCAN_STATE_INITIAL,
SCAN_STATE_INITIAL_MANIFEST,
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;
struct timeval last_send;
struct lws_spa *spa;
char filename[32];
char result[LWS_PRE + 512];
unsigned char buffer[4096];
int result_len;
int filename_length;
long file_length;
nvs_handle nvh;
char ap_record;
unsigned char subsequent:1;
unsigned char changed_partway:1;
};
struct per_vhost_data__esplws_scan {
wifi_ap_record_t ap_records[10];
TimerHandle_t timer, reboot_timer;
struct per_session_data__esplws_scan *live_pss_list;
struct lws_context *context;
struct lws_vhost *vhost;
const struct lws_protocols *protocol;
const esp_partition_t *part;
esp_ota_handle_t otahandle;
long file_length;
long content_length;
struct lws *cwsi;
char json[1024];
int json_len;
uint16_t count_ap_records;
char count_live_pss;
unsigned char scan_ongoing:1;
unsigned char completed_any_scan:1;
unsigned char reboot:1;
unsigned char changed_settings:1;
unsigned char checked_updates:1;
unsigned char autonomous_update:1;
unsigned char autonomous_update_sampled:1;
};
static const struct store_json store_json[] = {
{ "ssid\":\"", "ssid" },
{ ",\"pw\":\"", "password" },
{ ",\"access_pw\":\"", "access_pw" },
{ ",\"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;
const esp_partition_t *
ota_choose_part(void);
static const char * const param_names[] = {
"text",
"pub",
"pri",
"serial",
"opts",
};
enum enum_param_names {
EPN_TEXT,
EPN_PUB,
EPN_PRI,
EPN_SERIAL,
EPN_OPTS,
};
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)
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 reboot_timer_cb(TimerHandle_t t)
{
esp_restart();
}
static int
client_connection(struct per_vhost_data__esplws_scan *vhd, const char *file)
{
#if CONFIG_LWS_IS_FACTORY_APPLICATION == 'y' && defined(CONFIG_LWS_OTA_SERVER_BASE_URL) && \
defined(CONFIG_LWS_OTA_SERVER_FQDN)
static struct lws_client_connect_info i;
char path[256];
memset(&i, 0, sizeof i);
snprintf(path, sizeof(path) - 1, CONFIG_LWS_OTA_SERVER_BASE_URL "/" CONFIG_LWS_MODEL_NAME "/%s", file);
lwsl_notice("Fetching %s\n", path);
i.port = 443;
i.context = vhd->context;
i.address = CONFIG_LWS_OTA_SERVER_FQDN;
i.ssl_connection = 1;
i.host = i.address;
i.origin = i.host;
i.vhost = vhd->vhost;
i.method = "GET";
i.path = path;
i.protocol = "esplws-scan";
i.pwsi = &vhd->cwsi;
vhd->cwsi = lws_client_connect_via_info(&i);
if (!vhd->cwsi) {
lwsl_notice("NULL return\n");
return 1; /* fail */
}
#endif
return 0; /* ongoing */
}
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);
if (lws_esp32.inet && !vhd->cwsi && !vhd->checked_updates)
client_connection(vhd, "manifest.json");
if (vhd->changed_settings) {
lws_esp32_wlan_nvs_get(1);
vhd->changed_settings = 0;
} else
esp_wifi_connect();
}
static const char *ssl_names[] = { "ssl-pub.der", "ssl-pri.der" };
static int
file_upload_cb(void *data, const char *name, const char *filename,
char *buf, int len, enum lws_spa_fileupload_states state)
{
struct per_session_data__esplws_scan *pss =
(struct per_session_data__esplws_scan *)data;
int n;
switch (state) {
case LWS_UFS_OPEN:
if (lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
return -1;
lwsl_notice("LWS_UFS_OPEN Filename %s\n", filename);
strncpy(pss->filename, filename, sizeof(pss->filename) - 1);
if (!strcmp(name, "pub") || !strcmp(name, "pri")) {
if (nvs_open("lws-station", NVS_READWRITE, &pss->nvh))
return 1;
} else
return 1;
pss->file_length = 0;
break;
case LWS_UFS_FINAL_CONTENT:
case LWS_UFS_CONTENT:
if (len) {
/* if the file length is too big, drop it */
if (pss->file_length + len > sizeof(pss->buffer))
return 1;
memcpy(pss->buffer + pss->file_length, buf, len);
}
pss->file_length += len;
if (state == LWS_UFS_CONTENT)
break;
lwsl_notice("LWS_UFS_FINAL_CONTENT\n");
n = 0;
if (!strcmp(name, "pri"))
n = 1;
n = nvs_set_blob(pss->nvh, ssl_names[n], pss->buffer, pss->file_length);
if (n == ESP_OK)
nvs_commit(pss->nvh);
nvs_close(pss->nvh);
if (n != ESP_OK)
return 1;
break;
}
return 0;
}
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));
unsigned char *start = pss->buffer + LWS_PRE - 1, *p = start,
*end = pss->buffer + sizeof(pss->buffer) - 1;
wifi_ap_record_t *r;
int n, m;
nvs_handle nvh;
size_t s;
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;
strcpy(vhd->json, " { }");
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:
if (vhd->autonomous_update_sampled) {
p += snprintf((char *)p, end - p,
" {\n \"auton\":\"1\",\n \"pos\": \"%ld\",\n"
" \"len\":\"%ld\"\n}\n",
vhd->file_length,
vhd->content_length);
n = LWS_WRITE_TEXT;
goto issue;
}
switch (pss->scan_state) {
struct timeval t;
char ssid[32];
uint8_t mac[6];
struct lws_esp32_image i;
char img_factory[512], img_ota[512];
int grt;
case SCAN_STATE_INITIAL:
gettimeofday(&t, NULL);
if (t.tv_sec - pss->last_send.tv_sec < 10)
return 0;
pss->last_send = t;
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
n = 0;
if (nvs_get_blob(nvh, "ssl-pub.der", NULL, &s) == ESP_OK)
n = 1;
if (nvs_get_blob(nvh, "ssl-pri.der", NULL, &s) == ESP_OK)
n |= 2;
s = sizeof(ssid) - 1;
ssid[0] = '\0';
nvs_get_str(nvh, "ssid", ssid, &s);
nvs_close(nvh);
/*
* this value in the JSON is just
* used for UI indication. Each conditional feature confirms
* it itself before it allows itself to be used.
*/
grt = lws_esp32_get_reboot_type();
esp_efuse_read_mac(mac);
strcpy(img_factory, " { \"date\": \"Empty\" }");
strcpy(img_ota, " { \"date\": \"Empty\" }");
lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL), &i,
img_factory, sizeof(img_factory));
lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL), &i,
img_ota, sizeof(img_ota));
p += snprintf((char *)p, end - p,
"{ \"model\":\"%s\",\n"
" \"forced_button\":\"%d\",\n"
" \"serial\":\"%s\",\n"
" \"opts\":\"%s\",\n"
" \"host\":\"%s-%s\",\n"
" \"region\":\"%d\",\n"
" \"ssl_pub\":\"%d\",\n"
" \"ssl_pri\":\"%d\",\n"
" \"mac\":\"%02X%02X%02X%02X%02X%02X\",\n"
" \"ssid\":\"%s\",\n"
" \"conn_ip\":\"%s\",\n"
" \"conn_mask\":\"%s\",\n"
" \"conn_gw\":\"%s\",\n"
" \"img_factory\": %s,\n"
" \"img_ota\": %s,\n",
lws_esp32.model,
grt == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON,
lws_esp32.serial,
lws_esp32.opts,
lws_esp32.model, lws_esp32.serial,
lws_esp32.region,
n & 1, (n >> 1) & 1,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] | 1,
ssid,
lws_esp32.sta_ip,
lws_esp32.sta_mask,
lws_esp32.sta_gw,
img_factory,
img_ota
);
n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
pss->scan_state = SCAN_STATE_INITIAL_MANIFEST;
pss->ap_record = 0;
pss->subsequent = 0;
break;
case SCAN_STATE_INITIAL_MANIFEST:
p += snprintf((char *)p, end - p,
" \"latest\": %s,\n"
" \"inet\":\"%d\",\n",
vhd->json,
lws_esp32.inet
);
p += snprintf((char *)p, end - p,
" \"aps\":[\n");
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
pss->scan_state = SCAN_STATE_LIST;
break;
case SCAN_STATE_LIST:
for (m = 0; m < 6; m++) {
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((char *)p, end - p,
"{\"ssid\":\"%s\",\n"
"\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\n"
"\"rssi\":\"%d\",\n"
"\"chan\":\"%d\",\n"
"\"auth\":\"%d\"}\n",
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((char *)p, "]\n}\n");
if (pss->changed_partway) {
pss->subsequent = 0;
pss->scan_state = SCAN_STATE_INITIAL;
} else {
pss->scan_state = SCAN_STATE_NONE;
vhd->autonomous_update_sampled = vhd->autonomous_update;
}
break;
default:
return 0;
}
issue:
// lwsl_notice("issue: %d (%d)\n", p - start, n);
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:
{
const char *sect = "\"app\": {", *b;
nvs_handle nvh;
char p[64];
int n;
if (strstr((const char *)in, "identify")) {
lws_esp32_identify_physical_device();
break;
}
if (vhd->json_len && strstr((const char *)in, "update-factory")) {
sect = "\"factory\": {";
goto auton;
}
if (vhd->json_len && strstr((const char *)in, "update-ota"))
goto auton;
if (strstr((const char *)in, "reset"))
goto sched_reset;
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))
continue;
/* only change access password if he has physical access to device */
if (n == 2 && lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
continue;
lwsl_notice("%s '%s\n", store_json[n].nvs, p);
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);
if (lws_esp32_get_reboot_type() == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
if (strstr((const char *)in, "factory-reset")) {
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
nvs_erase_all(nvh);
nvs_commit(nvh);
nvs_close(nvh);
goto sched_reset;
}
}
if (vhd->scan_ongoing)
vhd->changed_settings = 1;
else
lws_esp32_wlan_nvs_get(1);
lwsl_notice("set Join AP info\n");
break;
bail_nvs:
nvs_close(nvh);
return 1;
sched_reset:
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
(TimerCallbackFunction_t)reboot_timer_cb);
xTimerStart(vhd->reboot_timer, 0);
return 1;
auton:
lwsl_notice("Autonomous upload\n");
b = strstr(vhd->json, sect);
if (!b) {
lwsl_notice("Can't find %s in JSON\n", sect);
return 1;
}
b = strstr(b, "\"file\": \"");
if (!b) {
lwsl_notice("Can't find \"file\": JSON\n");
return 1;
}
vhd->autonomous_update = 1;
if (pss->scan_state == SCAN_STATE_NONE)
vhd->autonomous_update_sampled = 1;
b += 9;
n = 0;
while ((*b != '\"') && n < sizeof(p) - 1)
p[n++] = *b++;
p[n] = '\0';
vhd->part = ota_choose_part();
if (!vhd->part)
return 1;
if (client_connection(vhd, p))
vhd->autonomous_update = 0;
break;
}
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;
/* "factory" POST handling */
case LWS_CALLBACK_HTTP_BODY:
/* create the POST argument parser if not already existing */
lwsl_notice("LWS_CALLBACK_HTTP_BODY (scan)\n");
if (!pss->spa) {
pss->spa = lws_spa_create(wsi, param_names,
ARRAY_SIZE(param_names), 1024,
file_upload_cb, pss);
if (!pss->spa)
return -1;
pss->filename[0] = '\0';
pss->file_length = 0;
}
/* let it parse the POST data */
if (lws_spa_process(pss->spa, in, len))
return -1;
break;
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION (scan)\n");
/* call to inform no more payload data coming */
lws_spa_finalize(pss->spa);
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
lwsl_err("Unable to open nvs\n");
break;
}
if (lws_esp32_get_reboot_type() == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
if (lws_spa_get_string(pss->spa, EPN_SERIAL)) {
if (nvs_set_str(nvh, "serial", lws_spa_get_string(pss->spa, EPN_SERIAL)) != ESP_OK) {
lwsl_err("Unable to store serial in nvm\n");
goto bail_nvs;
}
nvs_commit(nvh);
}
if (lws_spa_get_string(pss->spa, EPN_OPTS)) {
if (nvs_set_str(nvh, "opts", lws_spa_get_string(pss->spa, EPN_OPTS)) != ESP_OK) {
lwsl_err("Unable to store options in nvm\n");
goto bail_nvs;
}
nvs_commit(nvh);
}
}
nvs_close(nvh);
pss->result_len = snprintf(pss->result + LWS_PRE, sizeof(pss->result) - LWS_PRE - 1,
"<html>Rebooting after storing certs...<br>connect to AP '<b>config-%s-%s</b>' and continue here: "
"<a href=\"https://192.168.4.1\">https://192.168.4.1</a></html>",
lws_esp32.model, lws_spa_get_string(pss->spa, EPN_SERIAL));
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
goto bail;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)"text/html", 9, &p, end))
goto bail;
if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
goto bail;
if (lws_finalize_http_header(wsi, &p, end))
goto bail;
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
if (n < 0)
goto bail;
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_HTTP_WRITEABLE:
lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",
pss->result_len);
n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
pss->result_len, LWS_WRITE_HTTP);
if (n < 0)
return 1;
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(3000), 0, vhd,
(TimerCallbackFunction_t)reboot_timer_cb);
xTimerStart(vhd->reboot_timer, 0);
return 1; // hang up since we will reset
/* ----- client handling ----- */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
lwsl_notice("Client connection error %s\n", (char *)in);
vhd->cwsi = NULL;
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
if (!vhd->autonomous_update)
break;
{
char pp[20];
if (lws_hdr_copy(wsi, pp, sizeof(pp) - 1, WSI_TOKEN_HTTP_CONTENT_LENGTH) < 0)
return -1;
vhd->content_length = atoi(pp);
if (vhd->content_length <= 0 ||
vhd->content_length > vhd->part->size)
return -1;
if (esp_ota_begin(vhd->part, (long)-1, &vhd->otahandle) != ESP_OK) {
lwsl_err("OTA: Failed to begin\n");
return 1;
}
vhd->file_length = 0;
break;
}
break;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
//lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: %ld\n",
// (long)len);
if (!vhd->autonomous_update) {
if (sizeof(vhd->json) - vhd->json_len - 1 < len)
len = sizeof(vhd->json) - vhd->json_len - 1;
memcpy(vhd->json + vhd->json_len, in, len);
vhd->json_len += len;
vhd->json[vhd->json_len] = '\0';
break;
}
/* autonomous download */
if (vhd->file_length + len > vhd->part->size) {
lwsl_err("OTA: incoming file too large\n");
goto abort_ota;
}
lwsl_debug("writing 0x%lx... 0x%lx\n",
vhd->part->address + vhd->file_length,
vhd->part->address + vhd->file_length + len);
if (esp_ota_write(vhd->otahandle, in, len) != ESP_OK) {
lwsl_err("OTA: Failed to write\n");
goto abort_ota;
}
vhd->file_length += len;
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
break;
abort_ota:
esp_ota_end(vhd->otahandle);
vhd->otahandle = 0;
vhd->autonomous_update = 0;
return 1;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
{
char *px = (char *)pss->buffer + LWS_PRE;
int lenx = sizeof(pss->buffer) - LWS_PRE - 1;
//lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: %d\n", len);
if (lws_http_client_read(wsi, &px, &lenx) < 0)
return -1;
}
break;
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
lwsl_notice("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
vhd->cwsi = NULL;
if (!vhd->autonomous_update) {
vhd->checked_updates = 1;
puts(vhd->json);
return -1;
}
/* autonomous download */
lwsl_notice("auton complete\n");
if (esp_ota_end(vhd->otahandle) != ESP_OK) {
lwsl_err("OTA: end failed\n");
return 1;
}
if (esp_ota_set_boot_partition(vhd->part) != ESP_OK) {
lwsl_err("OTA: set boot part failed\n");
return 1;
}
vhd->otahandle = 0;
vhd->autonomous_update = 0;
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
(TimerCallbackFunction_t)reboot_timer_cb);
xTimerStart(vhd->reboot_timer, 0);
return -1;
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
lwsl_notice("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
break;
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
/* called when our wsi user_space is going to be destroyed */
if (pss->spa) {
lws_spa_destroy(pss->spa);
pss->spa = NULL;
}
break;
default:
break;
}
return 0;
bail:
return 1;
}
#define LWS_PLUGIN_PROTOCOL_ESPLWS_SCAN \
{ \
"esplws-scan", \
callback_esplws_scan, \
sizeof(struct per_session_data__esplws_scan), \
1024, 0, NULL, 900 \
}