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