1 /*
2 * lws-minimal-esp32
3 *
4 * Written in 2010-2020 by Andy Green <andy@warmcat.com>
5 *
6 * This file is made available under the Creative Commons CC0 1.0
7 * Universal Public Domain Dedication.
8 *
9 * Configured for ESP32 WROVER KIT
10 *
11 * What should be notable about this is there are no esp-idf apis used here or
12 * any related files, despite we are running on top of stock esp-idf.
13 */
14
15 #define LWIP_PROVIDE_ERRNO 1
16 #define _ESP_PLATFORM_ERRNO_H_
17
18 #include <stdio.h>
19 #include "sdkconfig.h"
20 #include "freertos/FreeRTOS.h"
21 #include "freertos/task.h"
22
23 #include <driver/gpio.h>
24
25 #include <libwebsockets.h>
26
27 struct lws_context *context;
28 extern struct lws_led_state *lls;
29 extern lws_display_state_t lds;
30 extern struct lws_button_state *bcs;
31 extern lws_netdev_instance_wifi_t *wnd;
32
33 lws_sorted_usec_list_t sul_pass;
34
35 extern int init_plat_devices(struct lws_context *);
36
37 static const uint8_t logo[] = {
38 #include "cat-565.h"
39 };
40
41 #if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
42 #include "static-policy.h"
43 #else
44 #include "policy.h"
45 #endif
46
47 static uint8_t flip;
48
49
50 typedef struct myss {
51 struct lws_ss_handle *ss;
52 void *opaque_data;
53 /* ... application specific state ... */
54
55 size_t amount;
56
57 } myss_t;
58
59 /*
60 * When we're actually happy we passed, we schedule the actual pass
61 * string to happen a few seconds later, so we can observe what the
62 * code did after the pass.
63 */
64
65 static void
completion_sul_cb(lws_sorted_usec_list_t * sul)66 completion_sul_cb(lws_sorted_usec_list_t *sul)
67 {
68 /*
69 * In CI, we use sai-expect to look for this
70 * string for success
71 */
72
73 lwsl_notice("Completed: PASS\n");
74 }
75
76 static int
myss_rx(void * userobj,const uint8_t * buf,size_t len,int flags)77 myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
78 {
79 myss_t *m = (myss_t *)userobj;
80
81 lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
82 // lwsl_hexdump_info(buf, len);
83 m->amount += len;
84
85 if (flags & LWSSS_FLAG_EOM) {
86
87 /*
88 * If we received the whole message, for our example it means
89 * we are done.
90 *
91 * Howevere we want to record what happened after we received
92 * the last bit so we can see anything unexpected coming. So
93 * wait 5s before sending the PASS magic.
94 */
95
96 lwsl_notice("%s: received %u bytes, passing in 10s\n",
97 __func__, (unsigned int)m->amount);
98
99 lws_sul_schedule(context, 0, &sul_pass, completion_sul_cb,
100 5 * LWS_US_PER_SEC);
101
102 return LWSSSSRET_DESTROY_ME;
103 }
104
105 return 0;
106 }
107
108 static int
myss_state(void * userobj,void * sh,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)109 myss_state(void *userobj, void *sh, lws_ss_constate_t state,
110 lws_ss_tx_ordinal_t ack)
111 {
112 myss_t *m = (myss_t *)userobj;
113
114 lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
115 (unsigned int)ack);
116
117 switch (state) {
118 case LWSSSCS_CREATING:
119 lws_ss_client_connect(m->ss);
120 break;
121 default:
122 break;
123 }
124
125 return 0;
126 }
127
128 static const lws_ss_info_t ssi = {
129 .handle_offset = offsetof(myss_t, ss),
130 .opaque_user_data_offset = offsetof(myss_t, opaque_data),
131 .rx = myss_rx,
132 .state = myss_state,
133 .user_alloc = sizeof(myss_t),
134 .streamtype = "test_stream",
135 };
136
137 static const lws_led_sequence_def_t *seqs[] = {
138 &lws_pwmseq_static_on,
139 &lws_pwmseq_static_off,
140 &lws_pwmseq_sine_endless_slow,
141 &lws_pwmseq_sine_endless_fast,
142 };
143
144 static int
smd_cb(void * opaque,lws_smd_class_t _class,lws_usec_t timestamp,void * buf,size_t len)145 smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp, void *buf,
146 size_t len)
147 {
148
149 if (!lws_json_simple_strcmp(buf, len, "\"src\":", "bc/user") &&
150 !lws_json_simple_strcmp(buf, len, "\"event\":", "click")) {
151 lws_led_transition(lls, "blue", seqs[flip & 3],
152 &lws_pwmseq_linear_wipe);
153 flip++;
154 }
155
156 lwsl_hexdump_notice(buf, len);
157
158 if ((_class & LWSSMDCL_SYSTEM_STATE) &&
159 !lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
160
161 /* create the secure stream */
162
163 lwsl_notice("%s: creating test secure stream\n", __func__);
164
165 if (lws_ss_create(context, 0, &ssi, NULL, NULL, NULL, NULL)) {
166 lwsl_err("%s: failed to create secure stream\n",
167 __func__);
168 return -1;
169 }
170 }
171
172 if (_class & LWSSMDCL_INTERACTION)
173 /*
174 * Any kind of user interaction brings the display back up and
175 * resets the dimming / blanking timers
176 */
177 lws_display_state_active(&lds);
178
179 return 0;
180 }
181
182 void
app_main(void)183 app_main(void)
184 {
185 struct lws_context_creation_info *info;
186
187 lws_set_log_level(1024 | 15, NULL);
188
189 lws_netdev_plat_init();
190 lws_netdev_plat_wifi_init();
191
192 info = malloc(sizeof(*info));
193 if (!info)
194 goto spin;
195
196 memset(info, 0, sizeof(*info));
197
198 lwsl_notice("LWS test for Espressif ESP32 WROVER KIT\n");
199
200 #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
201 info->pss_policies_json = ss_policy;
202 #else
203 info->pss_policies = &_ss_static_policy_entry;
204 #endif
205 info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
206 LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
207 info->port = CONTEXT_PORT_NO_LISTEN;
208 info->early_smd_cb = smd_cb;
209 info->early_smd_class_filter = LWSSMDCL_INTERACTION |
210 LWSSMDCL_SYSTEM_STATE |
211 LWSSMDCL_NETWORK;
212 info->smd_ttl_us = 20 * LWS_USEC_PER_SEC; /* we can spend a long time in display */
213
214 context = lws_create_context(info);
215 if (!context) {
216 lwsl_err("lws init failed\n");
217 goto spin;
218 }
219
220 /*
221 * We don't need this after context creation... things it pointed to
222 * still need to exist though since the context copied the pointers.
223 */
224
225 free(info);
226
227 /* devices and init are in devices.c */
228
229 if (init_plat_devices(context))
230 goto spin;
231
232 /* put the cat picture up there and enable the backlight */
233
234 lds.disp->blit(lds.disp, logo, 0, 0, 320, 240);
235 lws_display_state_active(&lds);
236
237 /* the lws event loop */
238
239 do {
240 taskYIELD();
241 lws_service(context, 0);
242 } while (1);
243
244 lwsl_notice("%s: exited event loop\n", __func__);
245
246
247 spin:
248 vTaskDelay(10);
249 taskYIELD();
250 goto spin;
251 }
252