2 * libwebsockets - lib/plat/lws-plat-esp32.c
4 * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 #include "core/private.h"
24 #include "misc/romfs.h"
25 #include <esp_ota_ops.h>
26 #include <tcpip_adapter.h>
27 #include <esp_image_format.h>
28 #include <esp_task_wdt.h>
29 #include "soc/ledc_reg.h"
30 #include "driver/ledc.h"
32 struct lws_esp32 lws_esp32 = {
33 .model = CONFIG_LWS_MODEL_NAME,
38 * Group AP / Station State
42 LWS_GAPSS_INITIAL, /* just started up, init and move to
45 * Unconnected, scanning: AP known in one of the
46 * config slots -> configure it, start timeout +
47 * LWS_GAPSS_STAT, if no AP already up in same
48 * group with lower MAC, after a random period
49 * start up our AP (LWS_GAPSS_AP)
52 * Trying to be the group AP... periodically do
53 * a scan LWS_GAPSS_AP_SCAN, faster and then
57 * doing a scan while trying to be the group
58 * AP... if we see a lower MAC being the AP for
59 * the same group AP, abandon being an AP and
60 * join that AP as a station
62 LWS_GAPSS_STAT_GRP_AP, /*
63 * We have decided to join another group member
64 * who is being the AP, as its MAC is lower than
65 * ours. This is a stable state, but we still
66 * do periodic scans LWS_GAPSS_STAT_GRP_AP_SCAN
67 * and will always prefer an AP configured in a
70 LWS_GAPSS_STAT_GRP_AP_SCAN,
72 * We have joined a group member who is doing
73 * the AP job... we want to check every now and
74 * then if a configured AP has appeared that we
75 * should better use instead. Otherwise stay in
76 * LWS_GAPSS_STAT_GRP_AP
79 * trying to connect to another non-group AP.
80 * If we don't get an IP within a timeout and
81 * retries, blacklist it and go back
86 static const char *gapss_str[] = {
91 "LWS_GAPSS_STAT_GRP_AP",
92 "LWS_GAPSS_STAT_GRP_AP_SCAN",
94 "LWS_GAPSS_STAT_HAPPY",
97 static romfs_t lws_esp32_romfs;
98 static TimerHandle_t leds_timer, scan_timer, debounce_timer, association_timer
99 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
103 static enum lws_gapss gapss = LWS_GAPSS_INITIAL;
104 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
105 static mdns_result_t *mdns_results_head;
111 const struct inode *i;
114 static void lws_gapss_to(enum lws_gapss to)
116 lwsl_notice("gapss from %s to %s\n", gapss_str[gapss], gapss_str[to]);
120 uint32_t lws_esp32_get_reboot_type(void)
122 uint32_t *p = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS, val = *p;
127 ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
128 if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
130 if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
135 * in the case the SSL certs are not there, don't require
136 * the button to be down to access all features.
139 val = LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON;
144 static void render_ip(char *dest, int len, uint8_t *ip)
146 snprintf(dest, len, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
149 void lws_esp32_restart_guided(uint32_t type)
151 uint32_t *p_force_factory_magic = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;
153 lwsl_notice("%s: %x\n", __func__, type);
154 *p_force_factory_magic = type;
160 * esp-idf goes crazy with zero length str nvs. Use this as a workaround
161 * to delete the key in that case.
164 esp_err_t lws_nvs_set_str(nvs_handle handle, const char* key, const char* value)
167 return nvs_set_str(handle, key, value);
169 return nvs_erase_key(handle, key);
172 static wifi_scan_config_t scan_config = {
179 static char scan_ongoing = 0, scan_timer_exists = 0;
180 static int try_slot = -1;
182 static wifi_config_t config = {
185 .authmode = WIFI_AUTH_OPEN,
192 static void lws_esp32_scan_timer_cb(TimerHandle_t th)
196 lwsl_notice("%s\n", __func__);
198 n = esp_wifi_scan_start(&scan_config, false);
200 lwsl_err("scan start failed %d\n", n);
203 static void lws_esp32_assoc_timer_cb(TimerHandle_t th)
207 xTimerStop(association_timer, 0);
209 if (gapss == LWS_GAPSS_STAT_HAPPY) {
210 lwsl_debug("%s: saw we were happy\n", __func__);
215 lwsl_notice("%s: forcing rescan\n", __func__);
217 lws_gapss_to(LWS_GAPSS_SCAN);
219 n = esp_wifi_scan_start(&scan_config, false);
221 lwsl_err("scan start failed %d\n", n);
225 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
227 void __attribute__(( weak ))
228 lws_group_member_event(int e, void *p)
232 void __attribute__(( weak ))
233 lws_get_iframe_size(int *w, int *h)
239 void lws_group_member_event_call(int e, void *p)
241 lws_group_member_event(e, p);
245 get_txt_param(const mdns_result_t *mr, const char *param, char *result, int len)
251 p = strstr(mr->txt->key, param);
257 lws_strncpy(result, mr->txt->value, len);
262 static void lws_esp32_mdns_timer_cb(TimerHandle_t th)
264 uint64_t now = lws_now_usecs();
265 struct lws_group_member *p, **p1;
266 const mdns_result_t *r = mdns_results_head;
269 char ch = 0, group[16];
271 get_txt_param(r, "group", group, sizeof(group));
272 if (strcmp(group, lws_esp32.group)) /* not our group */ {
273 lwsl_notice("group %s vs %s %s\n",
274 group, lws_esp32.group, r->txt->value);
280 if (strcmp(r->hostname, p->host))
282 if (memcmp(&r->addr, &p->addr, sizeof(r->addr)))
290 if (!p) { /* did not find */
293 p = lws_malloc(sizeof(*p), "group");
296 lws_strncpy(p->host, r->hostname, sizeof(p->host));
298 get_txt_param(r, "model", p->model, sizeof(p->model));
299 get_txt_param(r, "role", p->role, sizeof(p->role));
300 get_txt_param(r, "mac", p->mac, sizeof(p->mac));
301 get_txt_param(r, "width", temp, sizeof(temp));
302 p->width = atoi(temp);
303 get_txt_param(r, "height", temp, sizeof(temp));
304 p->height = atoi(temp);
306 memcpy(&p->addr, &r->addr, sizeof(p->addr));
307 // memcpy(&p->addrv6, &r->addrv6, sizeof(p->addrv6));
310 p->next = lws_esp32.first;
312 lws_esp32.extant_group_members++;
314 lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_ADD, p);
316 if (memcmp(&p->addr, &r->addr, sizeof(p->addr))) {
317 memcpy(&p->addr, &r->addr, sizeof(p->addr));
320 /* if (memcmp(&p->addrv6, &r->addrv6, sizeof(p->addrv6))) {
321 memcpy(&p->addrv6, &r->addrv6, sizeof(p->addrv6));
325 lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_CHANGE, p);
329 mdns_query_results_free(mdns_results_head);
331 /* garbage-collect group members not seen for too long */
332 p1 = &lws_esp32.first;
335 if (!(p->flags & LWS_GROUP_FLAG_SELF) &&
336 now - p->last_seen > 60000000) {
337 lws_esp32.extant_group_members--;
340 lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_REMOVE, p);
347 mdns_query_txt(lws_esp32.group, "_lwsgrmem", "_tcp", 0,
349 xTimerStart(mdns_timer, 0);
353 void __attribute__(( weak ))
354 lws_esp32_button(int down)
361 gpio_set_intr_type(GPIO_SW, GPIO_INTR_DISABLE);
362 xTimerStart(debounce_timer, 0);
365 static void lws_esp32_debounce_timer_cb(TimerHandle_t th)
367 if (lws_esp32.button_is_down)
368 gpio_set_intr_type(GPIO_SW, GPIO_INTR_POSEDGE);
370 gpio_set_intr_type(GPIO_SW, GPIO_INTR_NEGEDGE);
372 lws_esp32.button_is_down = gpio_get_level(GPIO_SW);
374 lws_esp32_button(lws_esp32.button_is_down);
381 /* if no APs configured, no point... */
383 if (!lws_esp32.ssid[0][0] &&
384 !lws_esp32.ssid[1][0] &&
385 !lws_esp32.ssid[2][0] &&
386 !lws_esp32.ssid[3][0])
389 if (scan_timer_exists && !scan_ongoing) {
390 // lwsl_notice("Starting scan timer...\n");
392 xTimerStart(scan_timer, 0);
403 wifi_ap_record_t ap_records[10];
404 uint16_t count_ap_records;
407 count_ap_records = LWS_ARRAY_SIZE(ap_records);
408 if (esp_wifi_scan_get_ap_records(&count_ap_records, ap_records)) {
409 lwsl_err("%s: failed\n", __func__);
413 if (!count_ap_records)
416 if (gapss != LWS_GAPSS_SCAN) {
417 lwsl_info("ignoring scan as gapss %s\n", gapss_str[gapss]);
421 /* no point if no APs set up */
422 if (!lws_esp32.ssid[0][0] &&
423 !lws_esp32.ssid[1][0] &&
424 !lws_esp32.ssid[2][0] &&
425 !lws_esp32.ssid[3][0])
428 lwsl_info("checking %d scan records\n", count_ap_records);
430 for (n = 0; n < 4; n++) {
432 if (!lws_esp32.ssid[(n + try_slot + 1) & 3][0])
435 lwsl_debug("looking for %s\n",
436 lws_esp32.ssid[(n + try_slot + 1) & 3]);
438 /* this ssid appears in scan results? */
440 for (m = 0; m < count_ap_records; m++) {
441 // lwsl_notice(" %s\n", ap_records[m].ssid);
442 if (!strcmp((char *)ap_records[m].ssid,
443 lws_esp32.ssid[(n + try_slot + 1) & 3]))
450 m = (n + try_slot + 1) & 3;
452 lwsl_info("Attempting connection with slot %d: %s:\n", m,
454 /* set the ssid we last tried to connect to */
455 lws_strncpy(lws_esp32.active_ssid, lws_esp32.ssid[m],
456 sizeof(lws_esp32.active_ssid));
458 lws_strncpy((char *)sta_config.sta.ssid, lws_esp32.ssid[m],
459 sizeof(sta_config.sta.ssid));
460 lws_strncpy((char *)sta_config.sta.password, lws_esp32.password[m],
461 sizeof(sta_config.sta.password));
463 tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA,
464 (const char *)&config.ap.ssid[7]);
465 lws_gapss_to(LWS_GAPSS_STAT);
466 xTimerStop(association_timer, 0);
467 xTimerStart(association_timer, 0);
469 esp_wifi_set_config(WIFI_IF_STA, &sta_config);
478 if (lws_esp32.scan_consumer)
479 lws_esp32.scan_consumer(count_ap_records, ap_records,
480 lws_esp32.scan_consumer_arg);
485 lws_set_genled(int n)
487 lws_esp32.genled_t = lws_now_usecs();
488 lws_esp32.genled = n;
492 lws_esp32_leds_network_indication(void)
495 int n, fadein = 100, speed = 1199, div = 1, base = 0;
498 us = r - lws_esp32.genled_t;
500 switch (lws_esp32.genled) {
501 case LWSESP32_GENLED__INIT:
502 lws_esp32.genled = LWSESP32_GENLED__LOST_NETWORK;
504 case LWSESP32_GENLED__LOST_NETWORK:
505 fadein = us / 10000; /* 100 steps in 1s */
508 lws_esp32.genled = LWSESP32_GENLED__NO_NETWORK;
511 case LWSESP32_GENLED__NO_NETWORK:
513 case LWSESP32_GENLED__CONN_AP:
518 case LWSESP32_GENLED__GOT_IP:
519 fadein = us / 10000; /* 100 steps in 1s */
522 lws_esp32.genled = LWSESP32_GENLED__OK;
524 fadein = 100 - fadein; /* we are fading out */
526 case LWSESP32_GENLED__OK:
527 if (lws_esp32.genled == LWSESP32_GENLED__OK)
536 n = base + (lws_esp32_sine_interp(r / speed) / div);
537 return (n * fadein) / 100;
540 esp_err_t lws_esp32_event_passthru(void *ctx, system_event_t *event)
542 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
543 struct lws_group_member *mem;
549 switch((int)event->event_id) {
550 case SYSTEM_EVENT_STA_START:
551 //esp_wifi_connect();
554 case SYSTEM_EVENT_STA_DISCONNECTED:
555 lwsl_notice("SYSTEM_EVENT_STA_DISCONNECTED\n");
558 lws_esp32.conn_ap = 0;
560 lws_esp32.sta_ip[0] = '\0';
561 lws_esp32.sta_mask[0] = '\0';
562 lws_esp32.sta_gw[0] = '\0';
563 lws_gapss_to(LWS_GAPSS_SCAN);
565 lws_set_genled(LWSESP32_GENLED__LOST_NETWORK);
570 case SYSTEM_EVENT_STA_CONNECTED:
571 lws_esp32.conn_ap = 1;
572 lws_set_genled(LWSESP32_GENLED__CONN_AP);
575 case SYSTEM_EVENT_STA_GOT_IP:
576 lwsl_notice("SYSTEM_EVENT_STA_GOT_IP\n");
579 lws_set_genled(LWSESP32_GENLED__GOT_IP);
581 render_ip(lws_esp32.sta_ip, sizeof(lws_esp32.sta_ip) - 1,
582 (uint8_t *)&event->event_info.got_ip.ip_info.ip);
583 render_ip(lws_esp32.sta_mask, sizeof(lws_esp32.sta_mask) - 1,
584 (uint8_t *)&event->event_info.got_ip.ip_info.netmask);
585 render_ip(lws_esp32.sta_gw, sizeof(lws_esp32.sta_gw) - 1,
586 (uint8_t *)&event->event_info.got_ip.ip_info.gw);
588 if (!nvs_open("lws-station", NVS_READWRITE, &nvh)) {
591 lws_snprintf(slot, sizeof(slot) - 1, "%duse", try_slot);
593 nvs_get_u32(nvh, slot, &use);
594 nvs_set_u32(nvh, slot, use + 1);
599 lws_gapss_to(LWS_GAPSS_STAT_HAPPY);
601 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
604 static mdns_txt_item_t txta[6];
605 static char wh[2][6];
608 mdns_hostname_set(lws_esp32.hostname);
609 mdns_instance_name_set(lws_esp32.group);
611 lws_get_iframe_size(&w, &h);
613 txta[0].key = "model";
614 txta[1].key = "group";
615 txta[2].key = "role";
617 txta[4].key = "width";
618 txta[5].key = "height";
620 txta[0].value = lws_esp32.model;
621 txta[1].value = lws_esp32.group;
622 txta[2].value = lws_esp32.role;
623 txta[3].value = lws_esp32.mac;
624 txta[4].value = wh[0];
625 txta[5].value = wh[1];
627 lws_snprintf(wh[0], 6, "%d", w);
628 lws_snprintf(wh[1], 6, "%d", h);
630 mdns_service_add(lws_esp32.group,
631 "_lwsgrmem", "_tcp", 443, txta,
632 LWS_ARRAY_SIZE(txta));
634 mem = lws_esp32.first;
642 struct lws_group_member *mem =
643 lws_malloc(sizeof(*mem), "group");
645 mem->last_seen = ~(uint64_t)0;
646 strcpy(mem->model, lws_esp32.model);
647 strcpy(mem->role, lws_esp32.role);
648 strcpy(mem->host, lws_esp32.hostname);
649 strcpy(mem->mac, lws_esp32.mac);
650 mem->flags = LWS_GROUP_FLAG_SELF;
651 lws_get_iframe_size(&mem->width,
654 &event->event_info.got_ip.ip_info.ip,
657 &event->event_info.got_ip6.ip6_info.ip,
658 sizeof(mem->addrv6));
659 mem->next = lws_esp32.first;
660 lws_esp32.first = mem;
661 lws_esp32.extant_group_members++;
663 lws_group_member_event_call(
664 LWS_SYSTEM_GROUP_MEMBER_ADD, mem);
666 } else { /* update our IP */
668 &event->event_info.got_ip.ip_info.ip,
671 &event->event_info.got_ip6.ip6_info.ip,
672 sizeof(mem->addrv6));
673 lws_group_member_event_call(
674 LWS_SYSTEM_GROUP_MEMBER_CHANGE, mem);
678 lwsl_err("unable to init mdns on STA: %d\n", n);
680 mdns_query_txt(lws_esp32.group, "_lwsgrmem", "_tcp", 0,
682 xTimerStart(mdns_timer, 0);
685 lwsl_notice(" --- Got IP %s\n", lws_esp32.sta_ip);
686 if (!sntp_enabled()) {
687 sntp_setoperatingmode(SNTP_OPMODE_POLL);
688 sntp_setservername(0, "pool.ntp.org");
693 case SYSTEM_EVENT_SCAN_DONE:
694 lwsl_notice("SYSTEM_EVENT_SCAN_DONE\n");
705 static lws_fop_fd_t IRAM_ATTR
706 esp32_lws_fops_open(const struct lws_plat_file_ops *fops, const char *filename,
707 const char *vfs_path, lws_fop_flags_t *flags)
709 struct esp32_file *f = malloc(sizeof(*f));
713 lwsl_notice("%s: %s\n", __func__, filename);
717 f->i = romfs_get_info(lws_esp32_romfs, filename, &len, &csum);
721 fop_fd = malloc(sizeof(*fop_fd));
726 fop_fd->filesystem_priv = f;
727 fop_fd->mod_time = csum;
728 *flags |= LWS_FOP_FLAG_MOD_TIME_VALID;
729 fop_fd->flags = *flags;
743 esp32_lws_fops_close(lws_fop_fd_t *fop_fd)
745 free((*fop_fd)->filesystem_priv);
752 static lws_fileofs_t IRAM_ATTR
753 esp32_lws_fops_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset_from_cur_pos)
755 fop_fd->pos += offset_from_cur_pos;
757 if (fop_fd->pos > fop_fd->len)
758 fop_fd->pos = fop_fd->len;
764 esp32_lws_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount, uint8_t *buf,
767 struct esp32_file *f = fop_fd->filesystem_priv;
770 lwsl_err("misaligned buf\n");
775 if (fop_fd->pos >= fop_fd->len)
778 if (len > fop_fd->len - fop_fd->pos)
779 len = fop_fd->len - fop_fd->pos;
781 spi_flash_read((uint32_t)(char *)f->i + fop_fd->pos, buf, len);
789 static const struct lws_plat_file_ops fops = {
791 .LWS_FOP_OPEN = esp32_lws_fops_open,
792 .LWS_FOP_CLOSE = esp32_lws_fops_close,
793 .LWS_FOP_READ = esp32_lws_fops_read,
794 .LWS_FOP_SEEK_CUR = esp32_lws_fops_seek_cur,
798 lws_esp32_wlan_nvs_get(int retry)
801 char lws_esp32_force_ap = 0, slot[12];
806 esp_efuse_mac_get_default(mac);
807 mac[5] |= 1; /* match the AP MAC */
808 snprintf(lws_esp32.serial, sizeof(lws_esp32.serial) - 1,
809 "%02X%02X%02X", mac[3], mac[4], mac[5]);
810 snprintf(lws_esp32.mac, sizeof(lws_esp32.mac) - 1,
811 "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3],
814 ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
816 config.sta.ssid[0] = '\0';
817 config.sta.password[0] = '\0';
819 for (n = 0; n < 4; n++) {
820 lws_snprintf(slot, sizeof(slot) - 1, "%dssid", n);
821 s = sizeof(lws_esp32.ssid[0]) - 1;
822 lws_esp32.ssid[n][0] = '\0';
823 nvs_get_str(nvh, slot, lws_esp32.ssid[n], &s);
825 lws_snprintf(slot, sizeof(slot) - 1, "%dpassword", n);
826 s = sizeof(lws_esp32.password[0]) - 1;
827 lws_esp32.password[n][0] = '\0';
828 nvs_get_str(nvh, slot, lws_esp32.password[n], &s);
831 s = sizeof(lws_esp32.serial) - 1;
832 if (nvs_get_str(nvh, "serial", lws_esp32.serial, &s) != ESP_OK)
833 lws_esp32_force_ap = 1;
835 snprintf((char *)config.ap.ssid, sizeof(config.ap.ssid) - 1,
836 "config-%s-%s", lws_esp32.model, lws_esp32.serial);
837 s = sizeof(lws_esp32.opts) - 1;
838 if (nvs_get_str(nvh, "opts", lws_esp32.opts, &s) != ESP_OK)
839 lws_esp32_force_ap = 1;
841 lws_esp32.access_pw[0] = '\0';
842 nvs_get_str(nvh, "access_pw", lws_esp32.access_pw, &s);
844 lws_esp32.group[0] = '\0';
845 s = sizeof(lws_esp32.group);
846 nvs_get_str(nvh, "group", lws_esp32.group, &s);
848 lws_esp32.role[0] = '\0';
849 s = sizeof(lws_esp32.role);
850 nvs_get_str(nvh, "role", lws_esp32.role, &s);
852 /* if group and role defined: group-role */
853 if (lws_esp32.group[0] && lws_esp32.role[0])
854 lws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,
855 "%s-%s", lws_esp32.group, lws_esp32.role);
856 else /* otherwise model-serial */
857 lws_snprintf(lws_esp32.hostname, sizeof(lws_esp32.hostname) - 1,
858 "%s-%s", lws_esp32.model, lws_esp32.serial);
862 lws_gapss_to(LWS_GAPSS_SCAN);
865 return lws_esp32_force_ap;
870 lws_esp32_wlan_config(void)
872 ledc_timer_config_t ledc_timer = {
873 .bit_num = LEDC_TIMER_13_BIT,
875 .speed_mode = LEDC_HIGH_SPEED_MODE,
876 .timer_num = LEDC_TIMER_0
880 lwsl_debug("%s\n", __func__);
882 ledc_timer_config(&ledc_timer);
884 lws_set_genled(LWSESP32_GENLED__INIT);
886 /* user code needs to provide lws_esp32_leds_timer_cb */
888 leds_timer = xTimerCreate("lws_leds", pdMS_TO_TICKS(25), 1, NULL,
889 (TimerCallbackFunction_t)lws_esp32_leds_timer_cb);
890 scan_timer = xTimerCreate("lws_scan", pdMS_TO_TICKS(10000), 0, NULL,
891 (TimerCallbackFunction_t)lws_esp32_scan_timer_cb);
892 debounce_timer = xTimerCreate("lws_db", pdMS_TO_TICKS(100), 0, NULL,
893 (TimerCallbackFunction_t)lws_esp32_debounce_timer_cb);
894 association_timer = xTimerCreate("lws_assoc", pdMS_TO_TICKS(10000), 0, NULL,
895 (TimerCallbackFunction_t)lws_esp32_assoc_timer_cb);
897 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
898 mdns_timer = xTimerCreate("lws_mdns", pdMS_TO_TICKS(5000), 0, NULL,
899 (TimerCallbackFunction_t)lws_esp32_mdns_timer_cb);
901 scan_timer_exists = 1;
902 xTimerStart(leds_timer, 0);
904 *(volatile uint32_t *)PERIPHS_IO_MUX_MTMS_U = FUNC_MTMS_GPIO14;
906 gpio_output_set(0, 0, 0, (1 << GPIO_SW));
908 n = gpio_install_isr_service(0);
912 c.intr_type = GPIO_INTR_NEGEDGE;
913 c.mode = GPIO_MODE_INPUT;
914 c.pin_bit_mask = 1 << GPIO_SW;
919 if (gpio_isr_handler_add(GPIO_SW, gpio_irq, NULL))
920 lwsl_notice("isr handler add for 14 failed\n");
922 lwsl_notice("failed to install gpio isr service: %d\n", n);
924 lws_esp32_wlan_nvs_get(0);
925 tcpip_adapter_init();
929 lws_esp32_wlan_start_ap(void)
931 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
933 ESP_ERROR_CHECK( esp_wifi_init(&cfg));
934 ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));
936 ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_APSTA) );
937 ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_AP, &config) );
938 ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
939 ESP_ERROR_CHECK( esp_wifi_start());
941 esp_wifi_scan_start(&scan_config, false);
943 if (sta_config.sta.ssid[0]) {
944 tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA,
945 (const char *)&config.ap.ssid[7]);
946 // esp_wifi_set_auto_connect(1);
947 ESP_ERROR_CHECK( esp_wifi_connect());
948 ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
949 ESP_ERROR_CHECK( esp_wifi_connect());
954 lws_esp32_wlan_start_station(void)
956 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
958 ESP_ERROR_CHECK( esp_wifi_init(&cfg));
959 ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));
961 ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA));
962 ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
964 ESP_ERROR_CHECK( esp_wifi_start());
966 tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA,
967 (const char *)&config.ap.ssid[7]);
968 //esp_wifi_set_auto_connect(1);
969 //ESP_ERROR_CHECK( esp_wifi_connect());
971 lws_esp32_scan_timer_cb(NULL);
974 const esp_partition_t *
975 lws_esp_ota_get_boot_partition(void)
977 const esp_partition_t *part = esp_ota_get_boot_partition(),
979 esp_image_header_t eih, ota_eih;
980 uint32_t *p_force_factory_magic = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;
982 /* confirm what we are told is the boot part is sane */
983 spi_flash_read(part->address , &eih, sizeof(eih));
984 factory_part = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
985 ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
986 ota = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
987 ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);
988 spi_flash_read(ota->address , &ota_eih, sizeof(ota_eih));
990 if (eih.spi_mode == 0xff ||
991 *p_force_factory_magic == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY ||
992 *p_force_factory_magic == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON
995 * we believed we were going to boot OTA, but we fell
996 * back to FACTORY in the bootloader when we saw it
997 * had been erased. esp_ota_get_boot_partition() still
998 * says the OTA partition then even if we are in the
999 * factory partition right now.
1001 part = factory_part;
1004 #ifdef CONFIG_LWS_IS_FACTORY_APPLICATION
1006 if (ota_eih.spi_mode != 0xff &&
1007 part->address != factory_part->address) {
1011 * we are a FACTORY image running in an OTA slot...
1012 * it means we were just written and need to copy
1013 * ourselves into the FACTORY slot.
1015 lwsl_notice("Copying FACTORY update into place "
1016 "0x%x len 0x%x\n", factory_part->address,
1017 factory_part->size);
1018 esp_task_wdt_reset();
1019 if (spi_flash_erase_range(factory_part->address,
1020 factory_part->size)) {
1021 lwsl_err("spi: Failed to erase\n");
1025 for (n = 0; n < factory_part->size; n += sizeof(buf)) {
1026 esp_task_wdt_reset();
1027 spi_flash_read(part->address + n , buf,
1029 if (spi_flash_write(factory_part->address + n,
1030 buf, sizeof(buf))) {
1031 lwsl_err("spi: Failed to write\n");
1037 * We send a message to the bootloader to erase the OTA header, we will come back up in
1038 * factory where the user can reload the OTA image
1040 lwsl_notice(" FACTORY copy successful, rebooting\n");
1041 lws_esp32_restart_guided(LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY_ERASE_OTA);
1052 lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
1054 const esp_partition_t *part;
1056 memset(info, 0, sizeof(*info));
1058 lws_set_log_level(63, lwsl_emit_syslog);
1060 part = lws_esp_ota_get_boot_partition();
1063 info->vhost_name = "default";
1065 info->fd_limit_per_thread = 16;
1066 info->max_http_header_pool = 5;
1067 info->max_http_header_data = 1024;
1068 info->pt_serv_buf_size = 4096;
1069 info->keepalive_timeout = 30;
1070 info->timeout_secs = 30;
1071 info->simultaneous_ssl_restriction = 2;
1072 info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
1073 LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
1077 lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
1078 char *json, int json_len)
1080 esp_image_segment_header_t eis;
1081 esp_image_header_t eih;
1084 spi_flash_read(part->address , &eih, sizeof(eih));
1085 hdr = part->address + sizeof(eih);
1087 if (eih.magic != ESP_IMAGE_HEADER_MAGIC) {
1088 lwsl_notice("%s: bad image header magic\n", __func__);
1093 while (eih.segment_count-- && eis.data_len != 0xffffffff) {
1094 spi_flash_read(hdr, &eis, sizeof(eis));
1095 hdr += sizeof(eis) + eis.data_len;
1097 hdr += (~hdr & 15) + 1;
1099 if (eih.hash_appended)
1102 // lwsl_notice("romfs estimated at 0x%x\n", hdr);
1104 i->romfs = hdr + 0x4;
1105 spi_flash_read(hdr, &i->romfs_len, sizeof(i->romfs_len));
1106 i->json = i->romfs + i->romfs_len + 4;
1107 spi_flash_read(i->json - 4, &i->json_len, sizeof(i->json_len));
1109 if (i->json_len < json_len - 1)
1110 json_len = i->json_len;
1111 spi_flash_read(i->json, json, json_len);
1112 json[json_len] = '\0';
1118 _rngf(void *context, unsigned char *buf, size_t len)
1120 if ((size_t)lws_get_random(context, buf, len) == len)
1127 lws_esp32_selfsigned(struct lws_vhost *vhost)
1129 mbedtls_x509write_cert crt;
1131 mbedtls_pk_context mpk;
1132 int buf_size = 4096, n;
1133 uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
1138 lwsl_notice("%s: %s\n", __func__, vhost->name);
1143 if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
1144 lwsl_notice("%s: can't open nvs\n", __func__);
1150 if (!nvs_get_blob(nvh, vhost->tls.alloc_cert_path, NULL, &s))
1152 if (!nvs_get_blob(nvh, vhost->tls.key_path, NULL, &s))
1157 lwsl_notice("%s: certs exist\n", __func__);
1159 return 0; /* certs already exist */
1162 lwsl_notice("%s: creating selfsigned initial certs\n", __func__);
1164 mbedtls_x509write_crt_init(&crt);
1166 mbedtls_pk_init(&mpk);
1167 if (mbedtls_pk_setup(&mpk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) {
1168 lwsl_notice("%s: pk_setup failed\n", __func__);
1171 lwsl_notice("%s: generating 2048-bit RSA keypair... "
1172 "this may take a minute or so...\n", __func__);
1173 n = mbedtls_rsa_gen_key(mbedtls_pk_rsa(mpk), _rngf, vhost->context,
1176 lwsl_notice("%s: failed to generate keys\n", __func__);
1179 lwsl_notice("%s: keys done\n", __func__);
1181 /* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
1183 lws_snprintf(subject, sizeof(subject) - 1,
1184 "C=TW,ST=New Taipei City,L=Taipei,O=warmcat,CN=%s",
1185 lws_esp32.hostname);
1187 if (mbedtls_x509write_crt_set_subject_name(&crt, subject)) {
1188 lwsl_notice("set SN failed\n");
1191 mbedtls_x509write_crt_set_subject_key(&crt, &mpk);
1192 if (mbedtls_x509write_crt_set_issuer_name(&crt, subject)) {
1193 lwsl_notice("set IN failed\n");
1196 mbedtls_x509write_crt_set_issuer_key(&crt, &mpk);
1198 lws_get_random(vhost->context, &n, sizeof(n));
1199 lws_snprintf(subject, sizeof(subject), "%d", n);
1201 mbedtls_mpi_init(&mpi);
1202 mbedtls_mpi_read_string(&mpi, 10, subject);
1203 mbedtls_x509write_crt_set_serial(&crt, &mpi);
1204 mbedtls_mpi_free(&mpi);
1206 mbedtls_x509write_crt_set_validity(&crt, "20171105235959",
1209 mbedtls_x509write_crt_set_key_usage(&crt,
1210 MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
1211 MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
1214 mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
1216 n = mbedtls_x509write_crt_pem(&crt, buf, buf_size, _rngf,
1219 lwsl_notice("%s: write crt der failed\n", __func__);
1223 lws_plat_write_cert(vhost, 0, 0, buf, strlen((const char *)buf));
1225 if (mbedtls_pk_write_key_pem(&mpk, buf, buf_size)) {
1226 lwsl_notice("write key pem failed\n");
1230 lws_plat_write_cert(vhost, 1, 0, buf, strlen((const char *)buf));
1232 mbedtls_pk_free(&mpk);
1233 mbedtls_x509write_crt_free(&crt);
1235 lwsl_notice("%s: cert creation complete\n", __func__);
1240 mbedtls_pk_free(&mpk);
1242 mbedtls_x509write_crt_free(&crt);
1251 lws_esp32_update_acme_info(void)
1255 n = lws_plat_read_file("acme-email", lws_esp32.le_email,
1256 sizeof(lws_esp32.le_email) - 1);
1258 lws_esp32.le_email[n] = '\0';
1260 n = lws_plat_read_file("acme-cn", lws_esp32.le_dns,
1261 sizeof(lws_esp32.le_dns) - 1);
1263 lws_esp32.le_dns[n] = '\0';
1266 struct lws_context *
1267 lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
1269 const esp_partition_t *part = lws_esp_ota_get_boot_partition();
1270 struct lws_context *context;
1271 struct lws_esp32_image i;
1272 struct lws_vhost *vhost;
1276 context = lws_create_context(info);
1277 if (context == NULL) {
1278 lwsl_err("Failed to create context\n");
1282 lws_esp32_get_image_info(part, &i, buf, sizeof(buf) - 1);
1284 lws_esp32_romfs = (romfs_t)i.romfs;
1285 if (!romfs_mount_check(lws_esp32_romfs)) {
1286 lwsl_err("mount error on ROMFS at %p 0x%x\n", lws_esp32_romfs,
1291 lwsl_notice("ROMFS length %uKiB\n", i.romfs_len >> 10);
1295 /* set the lws vfs to use our romfs */
1297 lws_set_fops(context, &fops);
1299 info->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX |
1300 LWS_SERVER_OPTION_IGNORE_MISSING_CERT;
1302 vhost = lws_create_vhost(context, info);
1304 lwsl_err("Failed to create vhost\n");
1308 lws_esp32_update_acme_info();
1310 lws_esp32_selfsigned(vhost);
1311 wsi.context = vhost->context;
1314 lws_tls_server_certs_load(vhost, &wsi, info->ssl_cert_filepath,
1315 info->ssl_private_key_filepath, NULL, 0, NULL, 0);
1317 lws_init_vhost_client_ssl(info, vhost);
1322 if (lws_protocol_init(context))
1328 static const uint16_t sineq16[] = {
1329 0x0000, 0x0191, 0x031e, 0x04a4, 0x061e, 0x0789, 0x08e2, 0x0a24,
1330 0x0b4e, 0x0c5c, 0x0d4b, 0x0e1a, 0x0ec6, 0x0f4d, 0x0faf, 0x0fea,
1333 static uint16_t sine_lu(int n)
1335 switch ((n >> 4) & 3) {
1337 return 4096 + sineq16[n & 15];
1339 return 4096 + sineq16[15 - (n & 15)];
1341 return 4096 - sineq16[n & 15];
1343 return 4096 - sineq16[15 - (n & 15)];
1347 /* useful for sine led fade patterns */
1349 uint16_t lws_esp32_sine_interp(int n)
1353 * 4: table entry in quadrant
1356 * total 10 bits / 1024 steps per cycle
1365 return (sine_lu(n >> 4) * (15 - (n & 15)) +
1366 sine_lu((n >> 4) + 1) * (n & 15)) / 15;