123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- /*
- * 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 \
- }
|