1 /*
2 * devices for ESP WROVER KIT
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
10 #define LWIP_PROVIDE_ERRNO 1
11 #define _ESP_PLATFORM_ERRNO_H_
12
13 #include <stdio.h>
14 #include "sdkconfig.h"
15 #include "freertos/FreeRTOS.h"
16 #include "freertos/task.h"
17
18 #include <driver/gpio.h>
19
20 #include <libwebsockets.h>
21
22 struct lws_led_state *lls;
23 lws_display_state_t lds;
24 struct lws_button_state *bcs;
25 lws_netdev_instance_wifi_t *wnd;
26
27 /*
28 * Button controller
29 *
30 * On the WROVER KIT, it's a bit overloaded... the two buttons are reset and
31 * gpio0, gpio is also used for one of the RGB LEDs channels control so it's not
32 * really usable as a general user button.
33 *
34 * Instead we use GPIO 14 (available on J1) for a button with the other side
35 * of the switch connected to 0V.
36 */
37
38 static const lws_button_map_t bcm[] = {
39 {
40 .gpio = GPIO_NUM_14,
41 .smd_interaction_name = "user"
42 },
43 };
44
45 static const lws_button_controller_t bc = {
46 .smd_bc_name = "bc",
47 .gpio_ops = &lws_gpio_plat,
48 .button_map = &bcm[0],
49 .active_state_bitmap = 0,
50 .count_buttons = LWS_ARRAY_SIZE(bcm),
51 };
52
53 /*
54 * pwm controller
55 */
56
57 static const lws_pwm_map_t pwm_map[] = {
58 { .gpio = GPIO_NUM_2, .index = 0, .active_level = 1 },
59 { .gpio = GPIO_NUM_0, .index = 1, .active_level = 1 },
60 { .gpio = GPIO_NUM_4, .index = 2, .active_level = 1 },
61 { .gpio = GPIO_NUM_5, .index = 3, .active_level = 0 }
62 };
63
64 static const lws_pwm_ops_t pwm_ops = {
65 lws_pwm_plat_ops,
66 .pwm_map = &pwm_map[0],
67 .count_pwm_map = LWS_ARRAY_SIZE(pwm_map)
68 };
69
70 /*
71 * led controller
72 */
73
74 static const lws_led_gpio_map_t lgm[] = {
75 {
76 .name = "red",
77 .gpio = GPIO_NUM_2,
78 .pwm_ops = &pwm_ops, /* managed by pwm */
79 .active_level = 1,
80 },
81 {
82 .name = "green",
83 .gpio = GPIO_NUM_0,
84 .pwm_ops = &pwm_ops, /* managed by pwm */
85 .active_level = 1,
86 },
87 {
88 .name = "blue",
89 .gpio = GPIO_NUM_4,
90 .pwm_ops = &pwm_ops, /* managed by pwm */
91 .active_level = 1,
92 },
93 {
94 .name = "backlight",
95 .gpio = GPIO_NUM_5,
96 .pwm_ops = &pwm_ops, /* managed by pwm */
97 .active_level = 0,
98 /*
99 * The wrover kit uses a 2 NPN in series to drive the backlight
100 * which means if the GPIO provides no current, the backlight is
101 * full-on. This causes a white flash during boot... they mark
102 * the first stage with "Modify In ESP-WROVER-KIT!" on the
103 * schematics but on Kit v4.1, it's still like that.
104 */
105 },
106 };
107
108 static const lws_led_gpio_controller_t lgc = {
109 .led_ops = lws_led_gpio_ops,
110 .gpio_ops = &lws_gpio_plat,
111 .led_map = &lgm[0],
112 .count_leds = LWS_ARRAY_SIZE(lgm)
113 };
114
115 /*
116 * Bitbang SPI configuration for display
117 */
118
119 static const lws_bb_spi_t lbspi = {
120 .bb_ops = {
121 lws_bb_spi_ops,
122 .bus_mode = LWS_SPI_BUSMODE_CLK_IDLE_LOW_SAMP_RISING
123 },
124 .gpio = &lws_gpio_plat,
125 .clk = GPIO_NUM_19,
126 .ncs = { GPIO_NUM_22 },
127 .ncmd = { GPIO_NUM_21 },
128 .mosi = GPIO_NUM_23,
129 .miso = GPIO_NUM_25,
130 .flags = LWSBBSPI_FLAG_USE_NCS0 |
131 LWSBBSPI_FLAG_USE_NCMD0
132 };
133
134 /*
135 * SPI display
136 */
137
138 static const lws_display_ili9341_t disp = {
139 .disp = {
140 lws_display_ili9341_ops,
141 .bl_pwm_ops = &pwm_ops,
142 .bl_active = &lws_pwmseq_static_on,
143 .bl_dim = &lws_pwmseq_static_half,
144 .bl_transition = &lws_pwmseq_linear_wipe,
145 .bl_index = 3,
146 .w = 320,
147 .h = 240,
148 .latency_wake_ms = 150,
149 },
150 .spi = (lws_spi_ops_t *)&lbspi,
151 .gpio = &lws_gpio_plat,
152 .reset_gpio = GPIO_NUM_18,
153 .spi_index = 0
154 };
155
156 /*
157 * Settings stored in platform nv
158 */
159
160 static const lws_settings_ops_t sett = {
161 lws_settings_ops_plat
162 };
163
164 /*
165 * Wifi
166 */
167
168 static const lws_netdev_ops_t wifi_ops = {
169 lws_netdev_wifi_plat_ops
170 };
171
172 int
init_plat_devices(struct lws_context * ctx)173 init_plat_devices(struct lws_context *ctx)
174 {
175 lws_settings_instance_t *si;
176 lws_netdevs_t *netdevs = lws_netdevs_from_ctx(ctx);
177
178 si = lws_settings_init(&sett, (void *)"nvs");
179 if (!si) {
180 lwsl_err("%s: failed to create settings instance\n", __func__);
181 return 1;
182 }
183 netdevs->si = si;
184
185 #if 0
186 /*
187 * This is a temp hack to bootstrap the settings to contain the test
188 * AP ssid and passphrase for one time, so the settings can be stored
189 * while there's no UI atm
190 */
191 {
192 lws_wifi_creds_t creds;
193
194 memset(&creds, 0, sizeof(creds));
195
196 lws_strncpy(creds.ssid, "xxx", sizeof(creds.ssid));
197 lws_strncpy(creds.passphrase, "yyy", sizeof(creds.passphrase));
198 lws_dll2_add_tail(&creds.list, &netdevs->owner_creds);
199
200 if (lws_netdev_credentials_settings_set(netdevs)) {
201 lwsl_err("%s: failed to write bootstrap creds\n",
202 __func__);
203 return 1;
204 }
205 }
206 #endif
207
208 // if (lws_netdev_instance_wifi_settings_get(si, "netdev.wl0", &niw, &ac)) {
209 // lwsl_err("%s: unable to fetch wl0 settings\n", __func__);
210 // return 1;
211 // }
212
213 /* create the wifi network device and configure it */
214
215 wnd = (lws_netdev_instance_wifi_t *)
216 wifi_ops.create(ctx, &wifi_ops, "wl0", NULL);
217 if (!wnd) {
218 lwsl_err("%s: failed to create wifi object\n", __func__);
219 return 1;
220 }
221
222 wnd->flags |= LNDIW_MODE_STA;
223
224 if (wifi_ops.configure(&wnd->inst, NULL)) {
225 lwsl_err("%s: failed to configure wifi object\n", __func__);
226 return 1;
227 }
228
229 wifi_ops.up(&wnd->inst);
230
231 /* bring up the led controller */
232
233 lls = lgc.led_ops.create(&lgc.led_ops);
234 if (!lls) {
235 lwsl_err("%s: could not create led\n", __func__);
236 return 1;
237 }
238
239 /* pwm init must go after the led controller init */
240
241 pwm_ops.init(&pwm_ops);
242
243 /* ... and the button controller */
244
245 bcs = lws_button_controller_create(ctx, &bc);
246 if (!bcs) {
247 lwsl_err("%s: could not create buttons\n", __func__);
248 return 1;
249 }
250
251 lws_button_enable(bcs, 0, lws_button_get_bit(bcs, "user"));
252
253 /* ... bring up spi bb and the display */
254
255 lbspi.bb_ops.init(&lbspi.bb_ops);
256 lws_display_state_init(&lds, ctx, 30000, 10000, lls, &disp.disp);
257
258 /*
259 * Make the RGB LED do something using sequenced PWM... pressing the
260 * GPIO14 button with single-presses advances the blue channel between
261 * different sequences
262 */
263
264 lws_led_transition(lls, "blue", &lws_pwmseq_sine_endless_fast,
265 &lws_pwmseq_linear_wipe);
266 lws_led_transition(lls, "green", &lws_pwmseq_sine_endless_slow,
267 &lws_pwmseq_linear_wipe);
268 lws_led_transition(lls, "red", &lws_pwmseq_sine_endless_slow,
269 &lws_pwmseq_linear_wipe);
270
271 return 0;
272 }
273