private.h: rename to contain dir
[platform/upstream/libwebsockets.git] / lib / plat / esp32 / esp32-helpers.c
1 /*
2  * libwebsockets - lib/plat/lws-plat-esp32.c
3  *
4  * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
5  *
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.
10  *
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.
15  *
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,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-lib-core.h"
23
24 #include "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"
31
32 struct lws_esp32 lws_esp32 = {
33         .model = CONFIG_LWS_MODEL_NAME,
34         .serial = "unknown",
35 };
36
37 /*
38  * Group AP / Station State
39  */
40
41 enum lws_gapss {
42         LWS_GAPSS_INITIAL,      /* just started up, init and move to
43                                  * LWS_GAPSS_SCAN */
44         LWS_GAPSS_SCAN,         /*
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)
50                                  */
51         LWS_GAPSS_AP,           /*
52                                  * Trying to be the group AP... periodically do
53                                  * a scan LWS_GAPSS_AP_SCAN, faster and then
54                                  * slower
55                                  */
56         LWS_GAPSS_AP_SCAN,      /*
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
61                                  */
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
68                                  * slot.
69                                  */
70         LWS_GAPSS_STAT_GRP_AP_SCAN,
71                                 /*
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
77                                  */
78         LWS_GAPSS_STAT,         /*
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
82                                  */
83         LWS_GAPSS_STAT_HAPPY,
84 };
85
86 static const char *gapss_str[] = {
87         "LWS_GAPSS_INITIAL",
88         "LWS_GAPSS_SCAN",
89         "LWS_GAPSS_AP",
90         "LWS_GAPSS_AP_SCAN",
91         "LWS_GAPSS_STAT_GRP_AP",
92         "LWS_GAPSS_STAT_GRP_AP_SCAN",
93         "LWS_GAPSS_STAT",
94         "LWS_GAPSS_STAT_HAPPY",
95 };
96
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)
100 , mdns_timer
101 #endif
102 ;
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;
106 #endif
107
108 #define GPIO_SW 14
109
110 struct esp32_file {
111         const struct inode *i;
112 };
113
114 static void lws_gapss_to(enum lws_gapss to)
115 {
116         lwsl_notice("gapss from %s to %s\n", gapss_str[gapss], gapss_str[to]);
117         gapss = to;
118 }
119
120 uint32_t lws_esp32_get_reboot_type(void)
121 {
122         uint32_t *p = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS, val = *p;
123         nvs_handle nvh;
124         size_t s = 0;
125         int n = 0;
126
127         ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
128         if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
129                 n = 1;
130         if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
131                 n |= 2;
132         nvs_close(nvh);
133
134         /*
135          * in the case the SSL certs are not there, don't require
136          * the button to be down to access all features.
137          */
138         if (n != 3)
139                 val = LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON;
140
141         return val;
142 }
143
144 static void render_ip(char *dest, int len, uint8_t *ip)
145 {
146         snprintf(dest, len, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
147 }
148
149 void lws_esp32_restart_guided(uint32_t type)
150 {
151         uint32_t *p_force_factory_magic = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;
152
153         lwsl_notice("%s: %x\n", __func__, type);
154         *p_force_factory_magic = type;
155
156         esp_restart();
157 }
158
159 /*
160  * esp-idf goes crazy with zero length str nvs.  Use this as a workaround
161  * to delete the key in that case.
162  */
163
164 esp_err_t lws_nvs_set_str(nvs_handle handle, const char* key, const char* value)
165 {
166         if (*value)
167                 return nvs_set_str(handle, key, value);
168
169         return nvs_erase_key(handle, key);
170 }
171
172 static wifi_scan_config_t scan_config = {
173         .ssid = 0,
174         .bssid = 0,
175         .channel = 0,
176         .show_hidden = true
177 };
178
179 static char scan_ongoing = 0, scan_timer_exists = 0;
180 static int try_slot = -1;
181
182 static wifi_config_t config = {
183         .ap = {
184             .channel = 6,
185             .authmode = WIFI_AUTH_OPEN,
186             .max_connection = 1,
187         } }, sta_config = {
188         .sta = {
189                 .bssid_set = 0,
190         } };
191
192 static void lws_esp32_scan_timer_cb(TimerHandle_t th)
193 {
194         int n;
195
196         lwsl_notice("%s\n", __func__);
197         scan_ongoing = 0;
198         n = esp_wifi_scan_start(&scan_config, false);
199         if (n != ESP_OK)
200                 lwsl_err("scan start failed %d\n", n);
201 }
202
203 static void lws_esp32_assoc_timer_cb(TimerHandle_t th)
204 {
205         int n;
206
207         xTimerStop(association_timer, 0);
208
209         if (gapss == LWS_GAPSS_STAT_HAPPY) {
210                 lwsl_debug("%s: saw we were happy\n", __func__);
211
212                 return;
213         }
214
215         lwsl_notice("%s: forcing rescan\n", __func__);
216
217         lws_gapss_to(LWS_GAPSS_SCAN);
218         scan_ongoing = 0;
219         n = esp_wifi_scan_start(&scan_config, false);
220         if (n != ESP_OK)
221                 lwsl_err("scan start failed %d\n", n);
222 }
223
224
225 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
226
227 void __attribute__(( weak ))
228 lws_group_member_event(int e, void *p)
229 {
230 }
231
232 void __attribute__(( weak ))
233 lws_get_iframe_size(int *w, int *h)
234 {
235         *w = 320;
236         *h = 160;
237 }
238
239 void lws_group_member_event_call(int e, void *p)
240 {
241         lws_group_member_event(e, p);
242 }
243
244 static int
245 get_txt_param(const mdns_result_t *mr, const char *param, char *result, int len)
246 {
247         const char *p;
248
249         *result = '\0';
250
251         p = strstr(mr->txt->key, param);
252         if (!p) {
253                 *result = '\0';
254                 return 1;
255         }
256
257         lws_strncpy(result, mr->txt->value, len);
258
259         return 0;
260 }
261
262 static void lws_esp32_mdns_timer_cb(TimerHandle_t th)
263 {
264         uint64_t now = lws_now_usecs();
265         struct lws_group_member *p, **p1;
266         const mdns_result_t *r = mdns_results_head;
267
268         while (r) {
269                 char ch = 0, group[16];
270
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);
275                         continue;
276                 }
277
278                 p = lws_esp32.first;
279                 while (p) {
280                         if (strcmp(r->hostname, p->host))
281                                 goto next;
282                         if (memcmp(&r->addr, &p->addr, sizeof(r->addr)))
283                                 goto next;
284
285                         p->last_seen = now;
286                         break;
287 next:
288                         p = p->next;
289                 }
290                 if (!p) { /* did not find */
291                         char temp[8];
292
293                         p = lws_malloc(sizeof(*p), "group");
294                         if (!p)
295                                 continue;
296                         lws_strncpy(p->host, r->hostname, sizeof(p->host));
297
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);
305
306                         memcpy(&p->addr, &r->addr, sizeof(p->addr));
307 //                      memcpy(&p->addrv6, &r->addrv6, sizeof(p->addrv6));
308                         p->last_seen = now;
309                         p->flags = 0;
310                         p->next = lws_esp32.first;
311                         lws_esp32.first = p;
312                         lws_esp32.extant_group_members++;
313
314                         lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_ADD, p);
315                 } else {
316                         if (memcmp(&p->addr, &r->addr, sizeof(p->addr))) {
317                                 memcpy(&p->addr, &r->addr, sizeof(p->addr));
318                                 ch = 1;
319                         }
320 /*                      if (memcmp(&p->addrv6, &r->addrv6, sizeof(p->addrv6))) {
321                                 memcpy(&p->addrv6, &r->addrv6, sizeof(p->addrv6));
322                                 ch = 1;
323                         } */
324                         if (ch)
325                                 lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_CHANGE, p);
326                 }
327         }
328
329         mdns_query_results_free(mdns_results_head);
330
331         /* garbage-collect group members not seen for too long */
332         p1 = &lws_esp32.first;
333         while (*p1) {
334                 p = *p1;
335                 if (!(p->flags & LWS_GROUP_FLAG_SELF) &&
336                                 now - p->last_seen > 60000000) {
337                         lws_esp32.extant_group_members--;
338                         *p1 = p->next;
339
340                         lws_group_member_event_call(LWS_SYSTEM_GROUP_MEMBER_REMOVE, p);
341                         lws_free(p);
342                         continue;
343                 }
344                 p1 = &(*p1)->next;
345         }
346
347         mdns_query_txt(lws_esp32.group, "_lwsgrmem", "_tcp", 0,
348                                &mdns_results_head);
349         xTimerStart(mdns_timer, 0);
350 }
351 #endif
352
353 void __attribute__(( weak ))
354 lws_esp32_button(int down)
355 {
356 }
357
358 void IRAM_ATTR
359 gpio_irq(void *arg)
360 {
361         gpio_set_intr_type(GPIO_SW, GPIO_INTR_DISABLE);
362         xTimerStart(debounce_timer, 0);
363 }
364
365 static void lws_esp32_debounce_timer_cb(TimerHandle_t th)
366 {
367         if (lws_esp32.button_is_down)
368                 gpio_set_intr_type(GPIO_SW, GPIO_INTR_POSEDGE);
369         else
370                 gpio_set_intr_type(GPIO_SW, GPIO_INTR_NEGEDGE);
371
372         lws_esp32.button_is_down = gpio_get_level(GPIO_SW);
373
374         lws_esp32_button(lws_esp32.button_is_down);
375 }
376
377
378 static int
379 start_scan()
380 {
381         /* if no APs configured, no point... */
382
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])
387                 return 0;
388
389         if (scan_timer_exists && !scan_ongoing) {
390                 // lwsl_notice("Starting scan timer...\n");
391                 scan_ongoing = 1;
392                 xTimerStart(scan_timer, 0);
393         }
394
395         return 0;
396 }
397
398
399
400 static void
401 end_scan()
402 {
403         wifi_ap_record_t ap_records[10];
404         uint16_t count_ap_records;
405         int n, m;
406
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__);
410                 return;
411         }
412
413         if (!count_ap_records)
414                 goto passthru;
415
416         if (gapss != LWS_GAPSS_SCAN) {
417                 lwsl_info("ignoring scan as gapss %s\n", gapss_str[gapss]);
418                 goto passthru;
419         }
420
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])
426                 goto passthru;
427
428         lwsl_info("checking %d scan records\n", count_ap_records);
429
430         for (n = 0; n < 4; n++) {
431
432                 if (!lws_esp32.ssid[(n + try_slot + 1) & 3][0])
433                         continue;
434
435                 lwsl_debug("looking for %s\n",
436                             lws_esp32.ssid[(n + try_slot + 1) & 3]);
437
438                 /* this ssid appears in scan results? */
439
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]))
444                                 goto hit;
445                 }
446
447                 continue;
448
449 hit:
450                 m = (n + try_slot + 1) & 3;
451                 try_slot = m;
452                 lwsl_info("Attempting connection with slot %d: %s:\n", m,
453                                 lws_esp32.ssid[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));
457
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));
462
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);
468
469                 esp_wifi_set_config(WIFI_IF_STA, &sta_config);
470                 esp_wifi_connect();
471                 break;
472         }
473
474         if (n == 4)
475                 start_scan();
476
477 passthru:
478         if (lws_esp32.scan_consumer)
479                 lws_esp32.scan_consumer(count_ap_records, ap_records,
480                                         lws_esp32.scan_consumer_arg);
481
482 }
483
484 static void
485 lws_set_genled(int n)
486 {
487         lws_esp32.genled_t = lws_now_usecs();
488         lws_esp32.genled = n;
489 }
490
491 int
492 lws_esp32_leds_network_indication(void)
493 {
494         uint64_t us, r;
495         int n, fadein = 100, speed = 1199, div = 1, base = 0;
496
497         r = lws_now_usecs();
498         us = r - lws_esp32.genled_t;
499
500         switch (lws_esp32.genled) {
501         case LWSESP32_GENLED__INIT:
502                 lws_esp32.genled = LWSESP32_GENLED__LOST_NETWORK;
503                 /* fallthru */
504         case LWSESP32_GENLED__LOST_NETWORK:
505                 fadein = us / 10000; /* 100 steps in 1s */
506                 if (fadein > 100) {
507                         fadein = 100;
508                         lws_esp32.genled = LWSESP32_GENLED__NO_NETWORK;
509                 }
510                 /* fallthru */
511         case LWSESP32_GENLED__NO_NETWORK:
512                 break;
513         case LWSESP32_GENLED__CONN_AP:
514                 base = 4096;
515                 speed = 933;
516                 div = 2;
517                 break;
518         case LWSESP32_GENLED__GOT_IP:
519                 fadein = us / 10000; /* 100 steps in 1s */
520                 if (fadein > 100) {
521                         fadein = 100;
522                         lws_esp32.genled = LWSESP32_GENLED__OK;
523                 }
524                 fadein = 100 - fadein; /* we are fading out */
525                 /* fallthru */
526         case LWSESP32_GENLED__OK:
527                 if (lws_esp32.genled == LWSESP32_GENLED__OK)
528                         return 0;
529
530                 base = 4096;
531                 speed = 766;
532                 div = 3;
533                 break;
534         }
535
536         n = base + (lws_esp32_sine_interp(r / speed) / div);
537         return (n * fadein) / 100;
538 }
539
540 esp_err_t lws_esp32_event_passthru(void *ctx, system_event_t *event)
541 {
542 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
543         struct lws_group_member *mem;
544         int n;
545 #endif
546         nvs_handle nvh;
547         uint32_t use;
548
549         switch((int)event->event_id) {
550         case SYSTEM_EVENT_STA_START:
551                 //esp_wifi_connect();
552 //              break;
553                 /* fallthru */
554         case SYSTEM_EVENT_STA_DISCONNECTED:
555                 lwsl_notice("SYSTEM_EVENT_STA_DISCONNECTED\n");
556                 if (sntp_enabled())
557                         sntp_stop();
558                 lws_esp32.conn_ap = 0;
559                 lws_esp32.inet = 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);
564                 mdns_free();
565                 lws_set_genled(LWSESP32_GENLED__LOST_NETWORK);
566                 start_scan();
567                 esp_wifi_connect();
568                 break;
569
570         case SYSTEM_EVENT_STA_CONNECTED:
571                 lws_esp32.conn_ap = 1;
572                 lws_set_genled(LWSESP32_GENLED__CONN_AP);
573                 break;
574
575         case SYSTEM_EVENT_STA_GOT_IP:
576                 lwsl_notice("SYSTEM_EVENT_STA_GOT_IP\n");
577
578                 lws_esp32.inet = 1;
579                 lws_set_genled(LWSESP32_GENLED__GOT_IP);
580
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);
587
588                 if (!nvs_open("lws-station", NVS_READWRITE, &nvh)) {
589                         char slot[8];
590
591                         lws_snprintf(slot, sizeof(slot) - 1, "%duse", try_slot);
592                         use = 0;
593                         nvs_get_u32(nvh, slot, &use);
594                         nvs_set_u32(nvh, slot, use + 1);
595                         nvs_commit(nvh);
596                         nvs_close(nvh);
597                 }
598
599                 lws_gapss_to(LWS_GAPSS_STAT_HAPPY);
600
601 #if !defined(CONFIG_LWS_IS_FACTORY_APPLICATION)
602                 n = mdns_init();
603                 if (!n) {
604                         static mdns_txt_item_t txta[6];
605                         static char wh[2][6];
606                         int w, h;
607
608                         mdns_hostname_set(lws_esp32.hostname);
609                         mdns_instance_name_set(lws_esp32.group);
610
611                         lws_get_iframe_size(&w, &h);
612
613                         txta[0].key = "model";
614                         txta[1].key = "group";
615                         txta[2].key = "role";
616                         txta[3].key = "mac";
617                         txta[4].key = "width";
618                         txta[5].key = "height";
619
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];
626
627                         lws_snprintf(wh[0], 6, "%d", w);
628                         lws_snprintf(wh[1], 6, "%d", h);
629
630                         mdns_service_add(lws_esp32.group,
631                                          "_lwsgrmem", "_tcp", 443, txta,
632                                          LWS_ARRAY_SIZE(txta));
633
634                         mem = lws_esp32.first;
635                         while (mem) {
636                                 if (mem->flags & 1)
637                                         break;
638                                 mem = mem->next;
639                         }
640
641                         if (!mem) {
642                                 struct lws_group_member *mem =
643                                               lws_malloc(sizeof(*mem), "group");
644                                 if (mem) {
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,
652                                                             &mem->height);
653                                         memcpy(&mem->addr,
654                                                &event->event_info.got_ip.ip_info.ip,
655                                                sizeof(mem->addr));
656                                         memcpy(&mem->addrv6,
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++;
662
663                                         lws_group_member_event_call(
664                                               LWS_SYSTEM_GROUP_MEMBER_ADD, mem);
665                                 }
666                         } else { /* update our IP */
667                                 memcpy(&mem->addr,
668                                        &event->event_info.got_ip.ip_info.ip,
669                                        sizeof(mem->addr));
670                                 memcpy(&mem->addrv6,
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);
675                         }
676
677                 } else
678                         lwsl_err("unable to init mdns on STA: %d\n", n);
679
680                 mdns_query_txt(lws_esp32.group, "_lwsgrmem", "_tcp", 0,
681                                &mdns_results_head);
682                 xTimerStart(mdns_timer, 0);
683 #endif
684
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");
689                         sntp_init();
690                 }
691                 break;
692
693         case SYSTEM_EVENT_SCAN_DONE:
694                 lwsl_notice("SYSTEM_EVENT_SCAN_DONE\n");
695                 end_scan();
696                 break;
697
698         default:
699                 break;
700         }
701
702         return ESP_OK;
703 }
704
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)
708 {
709         struct esp32_file *f = malloc(sizeof(*f));
710         lws_fop_fd_t fop_fd;
711         size_t len, csum;
712
713         lwsl_notice("%s: %s\n", __func__, filename);
714
715         if (!f)
716                 return NULL;
717         f->i = romfs_get_info(lws_esp32_romfs, filename, &len, &csum);
718         if (!f->i)
719                 goto bail;
720
721         fop_fd = malloc(sizeof(*fop_fd));
722         if (!fop_fd)
723                 goto bail;
724
725         fop_fd->fops = fops;
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;
730
731         fop_fd->len = len;
732         fop_fd->pos = 0;
733
734         return fop_fd;
735
736 bail:
737         free(f);
738
739         return NULL;
740 }
741
742 static int IRAM_ATTR
743 esp32_lws_fops_close(lws_fop_fd_t *fop_fd)
744 {
745         free((*fop_fd)->filesystem_priv);
746         free(*fop_fd);
747
748         *fop_fd = NULL;
749
750         return 0;
751 }
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)
754 {
755         fop_fd->pos += offset_from_cur_pos;
756
757         if (fop_fd->pos > fop_fd->len)
758                 fop_fd->pos = fop_fd->len;
759
760        return 0;
761 }
762
763 static int IRAM_ATTR
764 esp32_lws_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount, uint8_t *buf,
765                    lws_filepos_t len)
766 {
767        struct esp32_file *f = fop_fd->filesystem_priv;
768 #if 0
769        if ((long)buf & 3) {
770                lwsl_err("misaligned buf\n");
771
772                return -1;
773        }
774 #endif
775        if (fop_fd->pos >= fop_fd->len)
776                return 0;
777
778        if (len > fop_fd->len - fop_fd->pos)
779                len = fop_fd->len - fop_fd->pos;
780
781        spi_flash_read((uint32_t)(char *)f->i + fop_fd->pos, buf, len);
782
783        *amount = len;
784        fop_fd->pos += len;
785
786        return 0;
787 }
788
789 static const struct lws_plat_file_ops fops = {
790         .next = &fops_zip,
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,
795 };
796
797 int
798 lws_esp32_wlan_nvs_get(int retry)
799 {
800         nvs_handle nvh;
801         char lws_esp32_force_ap = 0, slot[12];
802         size_t s;
803         uint8_t mac[6];
804         int n;
805
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],
812                  mac[4], mac[5]);
813
814         ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
815
816         config.sta.ssid[0] = '\0';
817         config.sta.password[0] = '\0';
818
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);
824
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);
829         }
830
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;
834         else
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;
840
841         lws_esp32.access_pw[0] = '\0';
842         nvs_get_str(nvh, "access_pw", lws_esp32.access_pw, &s);
843
844         lws_esp32.group[0] = '\0';
845         s = sizeof(lws_esp32.group);
846         nvs_get_str(nvh, "group", lws_esp32.group, &s);
847
848         lws_esp32.role[0] = '\0';
849         s = sizeof(lws_esp32.role);
850         nvs_get_str(nvh, "role", lws_esp32.role, &s);
851
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);
859
860         nvs_close(nvh);
861
862         lws_gapss_to(LWS_GAPSS_SCAN);
863         start_scan();
864
865         return lws_esp32_force_ap;
866 }
867
868
869 void
870 lws_esp32_wlan_config(void)
871 {
872         ledc_timer_config_t ledc_timer = {
873                 .bit_num = LEDC_TIMER_13_BIT,
874                 .freq_hz = 5000,
875                 .speed_mode = LEDC_HIGH_SPEED_MODE,
876                 .timer_num = LEDC_TIMER_0
877         };
878         int n;
879
880         lwsl_debug("%s\n", __func__);
881
882         ledc_timer_config(&ledc_timer);
883
884         lws_set_genled(LWSESP32_GENLED__INIT);
885
886         /* user code needs to provide lws_esp32_leds_timer_cb */
887
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);
896
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);
900 #endif
901         scan_timer_exists = 1;
902         xTimerStart(leds_timer, 0);
903
904         *(volatile uint32_t *)PERIPHS_IO_MUX_MTMS_U = FUNC_MTMS_GPIO14;
905
906         gpio_output_set(0, 0, 0, (1 << GPIO_SW));
907
908         n = gpio_install_isr_service(0);
909         if (!n) {
910                 gpio_config_t c;
911
912                 c.intr_type = GPIO_INTR_NEGEDGE;
913                 c.mode = GPIO_MODE_INPUT;
914                 c.pin_bit_mask = 1 << GPIO_SW;
915                 c.pull_down_en = 0;
916                 c.pull_up_en = 0;
917                 gpio_config(&c);
918
919                 if (gpio_isr_handler_add(GPIO_SW, gpio_irq, NULL))
920                         lwsl_notice("isr handler add for 14 failed\n");
921         } else
922                 lwsl_notice("failed to install gpio isr service: %d\n", n);
923
924         lws_esp32_wlan_nvs_get(0);
925         tcpip_adapter_init();
926 }
927
928 void
929 lws_esp32_wlan_start_ap(void)
930 {
931         wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
932
933         ESP_ERROR_CHECK( esp_wifi_init(&cfg));
934         ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));
935
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());
940
941         esp_wifi_scan_start(&scan_config, false);
942
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());
950         }
951 }
952
953 void
954 lws_esp32_wlan_start_station(void)
955 {
956         wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
957
958         ESP_ERROR_CHECK( esp_wifi_init(&cfg));
959         ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM));
960
961         ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA));
962         ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config));
963
964         ESP_ERROR_CHECK( esp_wifi_start());
965
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());
970
971         lws_esp32_scan_timer_cb(NULL);
972 }
973
974 const esp_partition_t *
975 lws_esp_ota_get_boot_partition(void)
976 {
977         const esp_partition_t *part = esp_ota_get_boot_partition(),
978                               *factory_part, *ota;
979         esp_image_header_t eih, ota_eih;
980         uint32_t *p_force_factory_magic = (uint32_t *)LWS_MAGIC_REBOOT_TYPE_ADS;
981
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));
989
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
993         ) {
994                 /*
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.
1000                  */
1001                 part = factory_part;
1002         }
1003
1004 #ifdef CONFIG_LWS_IS_FACTORY_APPLICATION
1005         else
1006                 if (ota_eih.spi_mode != 0xff &&
1007                     part->address != factory_part->address) {
1008                         uint8_t buf[4096];
1009                         uint32_t n;
1010                         /*
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.
1014                          */
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");
1022                                 goto retry;
1023                         }
1024
1025                         for (n = 0; n < factory_part->size; n += sizeof(buf)) {
1026                                 esp_task_wdt_reset();
1027                                 spi_flash_read(part->address + n , buf,
1028                                                sizeof(buf));
1029                                 if (spi_flash_write(factory_part->address + n,
1030                                                     buf, sizeof(buf))) {
1031                                         lwsl_err("spi: Failed to write\n");
1032                                         goto retry;
1033                                 }
1034                         }
1035
1036                         /*
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
1039                          */
1040                         lwsl_notice("  FACTORY copy successful, rebooting\n");
1041                         lws_esp32_restart_guided(LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY_ERASE_OTA);
1042 retry:
1043                         esp_restart();
1044                 }
1045 #endif
1046
1047         return part;
1048 }
1049
1050
1051 void
1052 lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
1053 {
1054         const esp_partition_t *part;
1055
1056         memset(info, 0, sizeof(*info));
1057
1058         lws_set_log_level(63, lwsl_emit_syslog);
1059
1060         part = lws_esp_ota_get_boot_partition();
1061         (void)part;
1062
1063         info->vhost_name = "default";
1064         info->port = 443;
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;
1074 }
1075
1076 int
1077 lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
1078                          char *json, int json_len)
1079 {
1080         esp_image_segment_header_t eis;
1081         esp_image_header_t eih;
1082         uint32_t hdr;
1083
1084         spi_flash_read(part->address , &eih, sizeof(eih));
1085         hdr = part->address + sizeof(eih);
1086
1087         if (eih.magic != ESP_IMAGE_HEADER_MAGIC) {
1088                 lwsl_notice("%s: bad image header magic\n", __func__);
1089                 return 1;
1090         }
1091
1092         eis.data_len = 0;
1093         while (eih.segment_count-- && eis.data_len != 0xffffffff) {
1094                 spi_flash_read(hdr, &eis, sizeof(eis));
1095                 hdr += sizeof(eis) + eis.data_len;
1096         }
1097         hdr += (~hdr & 15) + 1;
1098
1099         if (eih.hash_appended)
1100                 hdr += 0x20;
1101
1102 //      lwsl_notice("romfs estimated at 0x%x\n", hdr);
1103
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));
1108
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';
1113
1114         return 0;
1115 }
1116
1117 static int
1118 _rngf(void *context, unsigned char *buf, size_t len)
1119 {
1120         if ((size_t)lws_get_random(context, buf, len) == len)
1121                 return 0;
1122
1123         return -1;
1124 }
1125
1126 int
1127 lws_esp32_selfsigned(struct lws_vhost *vhost)
1128 {
1129         mbedtls_x509write_cert crt;
1130         char subject[200];
1131         mbedtls_pk_context mpk;
1132         int buf_size = 4096, n;
1133         uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
1134         mbedtls_mpi mpi;
1135         nvs_handle nvh;
1136         size_t s;
1137
1138         lwsl_notice("%s: %s\n", __func__, vhost->name);
1139
1140         if (!buf)
1141                 return -1;
1142
1143         if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
1144                 lwsl_notice("%s: can't open nvs\n", __func__);
1145                 free(buf);
1146                 return 1;
1147         }
1148
1149         n = 0;
1150         if (!nvs_get_blob(nvh, vhost->tls.alloc_cert_path, NULL, &s))
1151                 n |= 1;
1152         if (!nvs_get_blob(nvh, vhost->tls.key_path, NULL, &s))
1153                 n |= 2;
1154
1155         nvs_close(nvh);
1156         if (n == 3) {
1157                 lwsl_notice("%s: certs exist\n", __func__);
1158                 free(buf);
1159                 return 0; /* certs already exist */
1160         }
1161
1162         lwsl_notice("%s: creating selfsigned initial certs\n", __func__);
1163
1164         mbedtls_x509write_crt_init(&crt);
1165
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__);
1169                 goto fail;
1170         }
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,
1174                                 2048, 65537);
1175         if (n) {
1176                 lwsl_notice("%s: failed to generate keys\n", __func__);
1177                 goto fail1;
1178         }
1179         lwsl_notice("%s: keys done\n", __func__);
1180
1181         /* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
1182
1183         lws_snprintf(subject, sizeof(subject) - 1,
1184                      "C=TW,ST=New Taipei City,L=Taipei,O=warmcat,CN=%s",
1185                      lws_esp32.hostname);
1186
1187         if (mbedtls_x509write_crt_set_subject_name(&crt, subject)) {
1188                 lwsl_notice("set SN failed\n");
1189                 goto fail1;
1190         }
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");
1194                 goto fail1;
1195         }
1196         mbedtls_x509write_crt_set_issuer_key(&crt, &mpk);
1197
1198         lws_get_random(vhost->context, &n, sizeof(n));
1199         lws_snprintf(subject, sizeof(subject), "%d", n);
1200
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);
1205
1206         mbedtls_x509write_crt_set_validity(&crt, "20171105235959",
1207                                            "20491231235959");
1208
1209         mbedtls_x509write_crt_set_key_usage(&crt,
1210                                             MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
1211                                             MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
1212
1213
1214         mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
1215
1216         n = mbedtls_x509write_crt_pem(&crt, buf, buf_size, _rngf,
1217                                       vhost->context);
1218         if (n < 0) {
1219                 lwsl_notice("%s: write crt der failed\n", __func__);
1220                 goto fail1;
1221         }
1222
1223         lws_plat_write_cert(vhost, 0, 0, buf, strlen((const char *)buf));
1224
1225         if (mbedtls_pk_write_key_pem(&mpk, buf, buf_size)) {
1226                 lwsl_notice("write key pem failed\n");
1227                 goto fail1;
1228         }
1229
1230         lws_plat_write_cert(vhost, 1, 0, buf, strlen((const char *)buf));
1231
1232         mbedtls_pk_free(&mpk);
1233         mbedtls_x509write_crt_free(&crt);
1234
1235         lwsl_notice("%s: cert creation complete\n", __func__);
1236
1237         return n;
1238
1239 fail1:
1240         mbedtls_pk_free(&mpk);
1241 fail:
1242         mbedtls_x509write_crt_free(&crt);
1243         free(buf);
1244
1245         nvs_close(nvh);
1246
1247         return -1;
1248 }
1249
1250 void
1251 lws_esp32_update_acme_info(void)
1252 {
1253         int n;
1254
1255         n = lws_plat_read_file("acme-email", lws_esp32.le_email,
1256                                sizeof(lws_esp32.le_email) - 1);
1257         if (n >= 0)
1258                 lws_esp32.le_email[n] = '\0';
1259
1260         n = lws_plat_read_file("acme-cn", lws_esp32.le_dns,
1261                                sizeof(lws_esp32.le_dns) - 1);
1262         if (n >= 0)
1263                 lws_esp32.le_dns[n] = '\0';
1264 }
1265
1266 struct lws_context *
1267 lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
1268 {
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;
1273         struct lws wsi;
1274         char buf[512];
1275
1276         context = lws_create_context(info);
1277         if (context == NULL) {
1278                 lwsl_err("Failed to create context\n");
1279                 return NULL;
1280         }
1281
1282         lws_esp32_get_image_info(part, &i, buf, sizeof(buf) - 1);
1283
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,
1287                          i.romfs);
1288                 return NULL;
1289         }
1290
1291         lwsl_notice("ROMFS length %uKiB\n", i.romfs_len >> 10);
1292
1293         puts(buf);
1294
1295         /* set the lws vfs to use our romfs */
1296
1297         lws_set_fops(context, &fops);
1298
1299         info->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX |
1300                          LWS_SERVER_OPTION_IGNORE_MISSING_CERT;
1301
1302         vhost = lws_create_vhost(context, info);
1303         if (!vhost) {
1304                 lwsl_err("Failed to create vhost\n");
1305                 return NULL;
1306         }
1307
1308         lws_esp32_update_acme_info();
1309
1310         lws_esp32_selfsigned(vhost);
1311         wsi.context = vhost->context;
1312         wsi.vhost = vhost;
1313
1314         lws_tls_server_certs_load(vhost, &wsi, info->ssl_cert_filepath,
1315                         info->ssl_private_key_filepath, NULL, 0, NULL, 0);
1316
1317         lws_init_vhost_client_ssl(info, vhost);
1318
1319         if (pvh)
1320                 *pvh = vhost;
1321
1322         if (lws_protocol_init(context))
1323                 return NULL;
1324
1325         return context;
1326 }
1327
1328 static const uint16_t sineq16[] = {
1329         0x0000, 0x0191, 0x031e, 0x04a4, 0x061e, 0x0789, 0x08e2, 0x0a24,
1330         0x0b4e, 0x0c5c, 0x0d4b, 0x0e1a, 0x0ec6, 0x0f4d, 0x0faf, 0x0fea,
1331 };
1332
1333 static uint16_t sine_lu(int n)
1334 {
1335         switch ((n >> 4) & 3) {
1336         case 1:
1337                 return 4096 + sineq16[n & 15];
1338         case 2:
1339                 return 4096 + sineq16[15 - (n & 15)];
1340         case 3:
1341                 return 4096 - sineq16[n & 15];
1342         default:
1343                 return  4096 - sineq16[15 - (n & 15)];
1344         }
1345 }
1346
1347 /* useful for sine led fade patterns */
1348
1349 uint16_t lws_esp32_sine_interp(int n)
1350 {
1351         /*
1352          * 2: quadrant
1353          * 4: table entry in quadrant
1354          * 4: interp (LSB)
1355          *
1356          * total 10 bits / 1024 steps per cycle
1357          *
1358          * +   0: 0
1359          * + 256: 4096
1360          * + 512: 8192
1361          * + 768: 4096
1362          * +1023: 0
1363          */
1364
1365         return (sine_lu(n >> 4) * (15 - (n & 15)) +
1366                 sine_lu((n >> 4) + 1) * (n & 15)) / 15;
1367 }