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
22struct lws_led_state *lls;
23lws_display_state_t lds;
24struct lws_button_state *bcs;
25lws_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
38static const lws_button_map_t bcm[] = {
39	{
40		.gpio			= GPIO_NUM_14,
41		.smd_interaction_name	= "user"
42	},
43};
44
45static 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
57static 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
64static 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
74static 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
108static 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
119static 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
138static 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
160static const lws_settings_ops_t sett = {
161	lws_settings_ops_plat
162};
163
164/*
165 * Wifi
166 */
167
168static const lws_netdev_ops_t wifi_ops = {
169	lws_netdev_wifi_plat_ops
170};
171
172int
173init_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