|
20 | 20 |
|
21 | 21 | -module(esp32init). |
22 | 22 |
|
23 | | --export([ |
24 | | - start/0, |
25 | | - start_repl/1, |
26 | | - start_network/0, |
27 | | - handle_req/3, |
28 | | - erase_net_config/0, |
29 | | - save_net_config/2 |
30 | | -]). |
31 | | - |
32 | | --record(nc_state, {socket, pending_pid, pending_ref}). |
33 | | - |
34 | | --define(DEFAULT_AP_SSID, <<"AtomVM-ESP32">>). |
35 | | --define(DEFAULT_AP_PSK, <<"esp32default">>). |
36 | | --define(DEFAULT_CONSOLE_PORT, 2323). |
37 | | --define(DEFAULT_WEB_SERVER_PORT, 8080). |
| 23 | +-export([start/0]). |
38 | 24 |
|
39 | 25 | start() -> |
40 | 26 | console:print(<<"AtomVM init.\n">>), |
@@ -63,24 +49,15 @@ loop() -> |
63 | 49 | maybe_start_dev_mode(SystemStatus) -> |
64 | 50 | case {SystemStatus, esp:nvs_get_binary(atomvm, dev_mode)} of |
65 | 51 | {_, <<"always">>} -> |
66 | | - start_dev_mode(); |
| 52 | + ep32devmode:start_dev_mode(); |
67 | 53 | {_, <<"never">>} -> |
68 | 54 | not_started; |
69 | 55 | {ok, undefined} -> |
70 | 56 | not_started; |
71 | 57 | {failed_app_start, undefined} -> |
72 | | - start_dev_mode() |
| 58 | + esp32devmode:start_dev_mode() |
73 | 59 | end. |
74 | 60 |
|
75 | | -start_dev_mode() -> |
76 | | - avm_pubsub:start(default_pubsub), |
77 | | - spawn(fun maybe_start_network/0), |
78 | | - started. |
79 | | - |
80 | | -%% |
81 | | -%% Boot handling |
82 | | -%% |
83 | | - |
84 | 61 | % TODO: add support for multiple apps |
85 | 62 | % /dev/partition/by-name/app1.avm |
86 | 63 | % /dev/partition/by-name/app2.avm |
@@ -119,275 +96,3 @@ get_start_module() -> |
119 | 96 | Module -> |
120 | 97 | erlang:binary_to_atom(Module, latin1) |
121 | 98 | end. |
122 | | - |
123 | | -%% |
124 | | -%% Network management |
125 | | -%% |
126 | | - |
127 | | -erase_net_config() -> |
128 | | - io:format("Erasing net config.~n"), |
129 | | - esp:nvs_erase_key(atomvm, sta_ssid), |
130 | | - esp:nvs_erase_key(atomvm, sta_psk). |
131 | | - |
132 | | -save_net_config(SSID, Pass) -> |
133 | | - io:format("Saving config: SSID: ~p Pass: ~p.~n", [SSID, Pass]), |
134 | | - esp:nvs_set_binary(atomvm, sta_ssid, erlang:list_to_binary(SSID)), |
135 | | - esp:nvs_set_binary(atomvm, sta_psk, erlang:list_to_binary(Pass)). |
136 | | - |
137 | | -get_net_config() -> |
138 | | - case esp:nvs_get_binary(atomvm, sta_ssid) of |
139 | | - undefined -> |
140 | | - get_default_net_config(); |
141 | | - SSID -> |
142 | | - case esp:nvs_get_binary(atomvm, sta_psk) of |
143 | | - undefined -> |
144 | | - get_default_net_config(); |
145 | | - Psk -> |
146 | | - get_net_config(SSID, Psk) |
147 | | - end |
148 | | - end. |
149 | | - |
150 | | -get_default_net_config() -> |
151 | | - Creds = [ |
152 | | - {ssid, ?DEFAULT_AP_SSID}, |
153 | | - {psk, ?DEFAULT_AP_PSK} |
154 | | - ], |
155 | | - {wait_for_ap, Creds}. |
156 | | - |
157 | | -get_net_config(SSID, Psk) -> |
158 | | - Creds = [ |
159 | | - {ssid, SSID}, |
160 | | - {psk, Psk} |
161 | | - ], |
162 | | - {wait_for_sta, Creds}. |
163 | | - |
164 | | -maybe_start_network() -> |
165 | | - case esp:nvs_get_binary(atomvm, wlan_enabled) of |
166 | | - undefined -> |
167 | | - start_network(); |
168 | | - <<"always">> -> |
169 | | - start_network(); |
170 | | - <<"never">> -> |
171 | | - not_started |
172 | | - end. |
173 | | - |
174 | | -start_network() -> |
175 | | - io:format("Starting network...~n"), |
176 | | - {WaitFunc, Creds} = get_net_config(), |
177 | | - case network:WaitFunc(Creds) of |
178 | | - ok -> |
179 | | - io:format("WLAN AP ready. Waiting connections.~n"), |
180 | | - Event = #{ |
181 | | - event => wlan_ap_started |
182 | | - }, |
183 | | - avm_pubsub:pub(default_pubsub, [system, network, wlan, connected], Event), |
184 | | - maybe_start_web_server(), |
185 | | - maybe_start_console(), |
186 | | - started; |
187 | | - {ok, {Address, Netmask, Gateway}} -> |
188 | | - io:format( |
189 | | - "Acquired IP address: ~s Netmask: ~s Gateway: ~s~n", |
190 | | - [to_string(Address), to_string(Netmask), to_string(Gateway)] |
191 | | - ), |
192 | | - Event = #{ |
193 | | - event => wlan_connected, |
194 | | - address => Address, |
195 | | - netmask => Netmask, |
196 | | - gateway => Gateway |
197 | | - }, |
198 | | - avm_pubsub:pub(default_pubsub, [system, network, wlan, connected], Event), |
199 | | - maybe_start_web_server(), |
200 | | - maybe_start_console(), |
201 | | - started; |
202 | | - Error -> |
203 | | - io:format("An error occurred starting network: ~p~n", [Error]), |
204 | | - not_started |
205 | | - end. |
206 | | - |
207 | | -to_string({{A, B, C, D}, Port}) -> |
208 | | - io_lib:format("~p.~p.~p.~p:~p", [A, B, C, D, Port]); |
209 | | -to_string({A, B, C, D}) -> |
210 | | - io_lib:format("~p.~p.~p.~p", [A, B, C, D]). |
211 | | - |
212 | | -%% |
213 | | -%% LISP |
214 | | -%% |
215 | | - |
216 | | -maybe_start_console() -> |
217 | | - case get_console_config() of |
218 | | - {always, Port} -> |
219 | | - listen(Port); |
220 | | - _ -> |
221 | | - io:format("ALISP console not enabled: skipping.~n"), |
222 | | - not_started |
223 | | - end. |
224 | | - |
225 | | -listen(Port) -> |
226 | | - case gen_tcp:listen(Port, []) of |
227 | | - {ok, ListenSocket} -> |
228 | | - io:format("ALISP console listening on port ~p~n", [Port]), |
229 | | - spawn(fun() -> accept(ListenSocket) end), |
230 | | - started; |
231 | | - Error -> |
232 | | - io:format("An error occurred listening: ~p~n", [Error]), |
233 | | - {error, Error} |
234 | | - end. |
235 | | - |
236 | | -get_console_config() -> |
237 | | - Enable = |
238 | | - case esp:nvs_get_binary(atomvm, console_enable) of |
239 | | - undefined -> |
240 | | - always; |
241 | | - <<"always">> -> |
242 | | - always; |
243 | | - <<"never">> -> |
244 | | - never |
245 | | - end, |
246 | | - Port = |
247 | | - case esp:nvs_get_binary(atomvm, console_port) of |
248 | | - undefined -> |
249 | | - ?DEFAULT_CONSOLE_PORT; |
250 | | - PortBinary -> |
251 | | - try erlang:binary_to_integer(PortBinary) of |
252 | | - PortInt -> PortInt |
253 | | - catch |
254 | | - Error -> |
255 | | - io:format("Unable to read ALISP console port: ~p.~n", [Error]), |
256 | | - ?DEFAULT_CONSOLE_PORT |
257 | | - end |
258 | | - end, |
259 | | - {Enable, Port}. |
260 | | - |
261 | | -accept(ListenSocket) -> |
262 | | - io:format("Waiting to accept shell connection...~n"), |
263 | | - case gen_tcp:accept(ListenSocket) of |
264 | | - {ok, Socket} -> |
265 | | - spawn_opt(?MODULE, start_repl, [self()], [link]), |
266 | | - io:format("Accepted shell connection. local: ~s peer: ~s~n", [ |
267 | | - local_address(Socket), peer_address(Socket) |
268 | | - ]), |
269 | | - spawn(fun() -> accept(ListenSocket) end), |
270 | | - loop(#nc_state{socket = Socket}); |
271 | | - Error -> |
272 | | - io:format("An error occurred accepting connection: ~p~n", [Error]) |
273 | | - end. |
274 | | - |
275 | | -loop(State) -> |
276 | | - receive |
277 | | - {tcp_closed, _Socket} -> |
278 | | - io:format("Connection closed.~n"), |
279 | | - erlang:exit(connection_closed); |
280 | | - {tcp, _Socket, <<255, 244, 255, 253, 6>>} -> |
281 | | - io:format("Break.~n"), |
282 | | - gen_tcp:close(State#nc_state.socket), |
283 | | - erlang:exit(break); |
284 | | - {tcp, _Socket, Packet} -> |
285 | | - Reply = {io_reply, State#nc_state.pending_ref, Packet}, |
286 | | - State#nc_state.pending_pid ! Reply, |
287 | | - loop(State#nc_state{pending_pid = undefined, pending_ref = undefined}); |
288 | | - {io_request, FPid, FRef, Request} -> |
289 | | - {ok, NewState} = io_request(Request, FPid, FRef, State), |
290 | | - loop(NewState) |
291 | | - end. |
292 | | - |
293 | | -local_address(Socket) -> |
294 | | - {ok, SockName} = inet:sockname(Socket), |
295 | | - to_string(SockName). |
296 | | - |
297 | | -peer_address(Socket) -> |
298 | | - {ok, Peername} = inet:peername(Socket), |
299 | | - to_string(Peername). |
300 | | - |
301 | | -start_repl(SocketIOLeader) -> |
302 | | - erlang:group_leader(SocketIOLeader, self()), |
303 | | - arepl:start(). |
304 | | - |
305 | | -io_request({get_line, unicode, Data}, FPid, FRef, State) -> |
306 | | - gen_tcp:send(State#nc_state.socket, Data), |
307 | | - {ok, State#nc_state{pending_pid = FPid, pending_ref = FRef}}; |
308 | | -io_request({put_chars, unicode, Data}, FPid, FRef, State) -> |
309 | | - gen_tcp:send(State#nc_state.socket, Data), |
310 | | - FPid ! {io_reply, FRef, ok}, |
311 | | - {ok, State}. |
312 | | - |
313 | | -%% |
314 | | -%% Web Server |
315 | | -%% |
316 | | - |
317 | | -maybe_start_web_server() -> |
318 | | - case get_web_server_config() of |
319 | | - {always, Port} -> |
320 | | - Router = [ |
321 | | - {"*", ?MODULE, []} |
322 | | - ], |
323 | | - http_server:start_server(Port, Router), |
324 | | - io:format("Web server listening on port ~p~n", [Port]), |
325 | | - started; |
326 | | - _ -> |
327 | | - io:format("Web server not enabled: skipping.~n"), |
328 | | - not_started |
329 | | - end. |
330 | | - |
331 | | -get_web_server_config() -> |
332 | | - Enable = |
333 | | - case esp:nvs_get_binary(atomvm, web_server_enable) of |
334 | | - undefined -> |
335 | | - always; |
336 | | - <<"always">> -> |
337 | | - always; |
338 | | - <<"never">> -> |
339 | | - never |
340 | | - end, |
341 | | - Port = |
342 | | - case esp:nvs_get_binary(atomvm, web_server_port) of |
343 | | - undefined -> |
344 | | - ?DEFAULT_WEB_SERVER_PORT; |
345 | | - PortBinary -> |
346 | | - try erlang:binary_to_integer(PortBinary) of |
347 | | - PortInt -> PortInt |
348 | | - catch |
349 | | - Error -> |
350 | | - io:format("Unable to read web server port: ~p.~n", [Error]), |
351 | | - ?DEFAULT_WEB_SERVER_PORT |
352 | | - end |
353 | | - end, |
354 | | - {Enable, Port}. |
355 | | - |
356 | | -handle_req("GET", [], Conn) -> |
357 | | - Body = |
358 | | - << |
359 | | - "<html>\n" |
360 | | - " <body>\n" |
361 | | - " <h1>Configuration</h1>\n" |
362 | | - " <form method=\"post\">\n" |
363 | | - " <p>SSID: <input type=\"text\" name=\"ssid\"></p>\n" |
364 | | - " <p>Pass: <input type=\"text\" name=\"pass\"></p>\n" |
365 | | - " <input type=\"submit\" value=\"Submit\">\n" |
366 | | - " </form>\n" |
367 | | - " </body>\n" |
368 | | - "</html>" |
369 | | - >>, |
370 | | - http_server:reply(200, Body, Conn); |
371 | | -handle_req("POST", [], Conn) -> |
372 | | - ParamsBody = proplists:get_value(body_chunk, Conn), |
373 | | - Params = http_server:parse_query_string(ParamsBody), |
374 | | - |
375 | | - SSID = proplists:get_value("ssid", Params), |
376 | | - Pass = proplists:get_value("pass", Params), |
377 | | - save_net_config(SSID, Pass), |
378 | | - |
379 | | - Body = |
380 | | - << |
381 | | - "<html>\n" |
382 | | - " <body>\n" |
383 | | - " <h1>Configuration</h1>\n" |
384 | | - " <p>Configured.</p>\n" |
385 | | - " </body>\n" |
386 | | - "</html>" |
387 | | - >>, |
388 | | - http_server:reply(200, Body, Conn); |
389 | | -handle_req(Method, Path, Conn) -> |
390 | | - erlang:display(Conn), |
391 | | - erlang:display({Method, Path}), |
392 | | - Body = <<"<html><body><h1>Not Found</h1></body></html>">>, |
393 | | - http_server:reply(404, Body, Conn). |
0 commit comments