Skip to content

Commit 29e7558

Browse files
committed
Update the ESP32 network driver.
This PR updates the ESP32 network driver. Changes include: * Revision to driver to conform to contributing guidelines * Update use of ESP IDF SDK to not use deprecated operations * Add support for SNTP * Add support for sntp_synchronized callback (thank you @pgoyout) * Fix socket tests by using the same esp-idf API * Updated docs and example program Signed-off-by: Fred Dushin <[email protected]>
1 parent 66dcbae commit 29e7558

File tree

10 files changed

+620
-427
lines changed

10 files changed

+620
-427
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4343
- Added support for serializing floats in erlang external term encoding
4444
- Added support for the `SMALL_BIG_EXT` erlang external term encoding
4545
- Added support for `erlang:memory(binary)`
46-
46+
- Added support for callbacks on SNTP updates
4747

4848
### Fixed
4949
- Fixed issue with formatting integers with io:format() on STM32 platform
5050
- Fixed a bug in the order of child initialization in the `supervisor` module
5151
- Fixed a bug in the evaluation of `receive ... after infinity -> ...` expressions
5252
- Fixed a bug in when putting integers in bit syntax with integer field sizes
5353
- Fixed numerous bugs in memory allocations that could crash the VM
54+
- Fixed SNTP support that had been broken in IDF 4.x builds
5455

5556
### Breaking Changes
5657

doc/src/network-programming-guide.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,25 @@ In order to enable both STA and AP mode, simply provide valid configuration for
194194

195195
You may configure the networking layer to automatically synchronize time on the ESP32 with an NTP server accessible on the network.
196196

197-
To synchronize time with an NTP server, add a property list with the tag `sntp` at the top level configuration passed into the `network:start/1` function. Specify the NTP hostname or IP address with which your device should sync using the `endpoint` property tag, e.g.,
197+
To synchronize time with an NTP server, add a property list with the tag `sntp` at the top level configuration passed into the `network:start/1` function. Specify the NTP hostname or IP address with which your device should sync using the `host` property tag. The `host` value can be a string or binary.
198198

199-
{sntp, [{endpoint, <<"pool.ntp.org">>}]}
199+
You can also specify a callback function that will get called when the clock is synchronized with the SNTP server via the `synchronized` property tag. This function takes a tuple with the updated time in seconds and microseconds.
200200

201-
The endpoint value can be a string or binary.
201+
For example:
202+
203+
%% erlang
204+
{sntp, [
205+
{host, <<"pool.ntp.org">>},
206+
{synchronized, fun sntp_synchronized/1}
207+
]}
208+
209+
where the `sntp_synchronized/1` function is defined as:
210+
211+
%% erlang
212+
sntp_synchronized({TVSec, TVUsec}) ->
213+
io:format("Synchronized time with SNTP server. TVSec=~p TVUsec=~p~n", [TVSec, TVUsec]).
214+
215+
> Note. The device must be in STA mode and connected to an access point in order to use an SNTP server on your network or on the internet.
202216
203217
## NVS Credentials
204218

doc/src/programmers-guide.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,10 @@ For information about how to handle connections and disconnections from attached
10821082

10831083
For information about how to run the AtomVM network in STA and AP mode simultaneously, see the [AtomVM Network Programming Guide](./network-programming-guide.md).
10841084

1085+
#### SNTP
1086+
1087+
For information about how to use SNTP to synchronize the clock on your device, see the [AtomVM Network Programming Guide](./network-programming-guide.md).
1088+
10851089
### UDP
10861090

10871091
AtomVM supports network programming using the User Datagram Protocol (UDP) via the `gen_udp` module. This modules obeys the syntax and semantics of the Erlang/OTP [`gen_udp`](https://erlang.org/doc/man/gen_udp.html) interface.

examples/erlang/esp32/ap_sta_network.erl

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,24 @@ start() ->
3535
{ap_started, fun ap_started/0},
3636
{sta_connected, fun sta_connected/1},
3737
{sta_ip_assigned, fun sta_ip_assigned/1},
38-
{sta_disconnected, fun sta_disconnected/1}
38+
{sta_disconnected, fun sta_disconnected/1},
39+
{ap_sta_ip_assigned, fun ap_sta_ip_assigned/1}
3940
]},
4041
{sta, [
41-
{ssid, esp:nvs_get_binary(atomvm, sta_ssid, <<"myssid">>)},
42-
{psk, esp:nvs_get_binary(atomvm, sta_psk, <<"mypsk">>)},
42+
{ssid, <<"myssid">>},
43+
{psk, <<"mypsk">>},
4344
{connected, fun connected/0},
4445
{got_ip, fun got_ip/1},
4546
{disconnected, fun disconnected/0}
4647
]},
47-
{sntp, [{endpoint, "pool.ntp.org"}]}
48+
{sntp, [
49+
{host, "pool.ntp.org"},
50+
{synchronized, fun sntp_synchronized/1}
51+
]}
4852
],
4953
case network:start(Config) of
5054
{ok, _Pid} ->
51-
sleep_forever();
55+
timer:sleep(infinity);
5256
Error ->
5357
erlang:display(Error)
5458
end.
@@ -74,6 +78,8 @@ got_ip(IpInfo) ->
7478
disconnected() ->
7579
io:format("STA disconnected.~n").
7680

77-
sleep_forever() ->
78-
timer:sleep(10000),
79-
sleep_forever().
81+
ap_sta_ip_assigned(Address) ->
82+
io:format("AP assigned STA address ~p~n", [Address]).
83+
84+
sntp_synchronized({TVSec, TVUsec}) ->
85+
io:format("Synchronized time with SNTP server. TVSec=~p TVUsec=~p~n", [TVSec, TVUsec]).

libs/eavmlib/src/network.erl

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,12 @@
9898
| ap_sta_ip_assigned_config().
9999
-type ap_config() :: {sta, [ap_config_property()]}.
100100

101-
-type sntp_config_property() :: {host, string() | binary()}.
101+
-type sntp_host_config() :: {host, string() | binary()}.
102+
-type sntp_synchronized_config() ::
103+
{synchronized, fun(({non_neg_integer(), non_neg_integer()}) -> term())}.
104+
-type sntp_config_property() ::
105+
sntp_host_config()
106+
| sntp_synchronized_config().
102107
-type sntp_config() :: {sntp, [sntp_config_property()]}.
103108

104109
-type network_config() :: [sta_config() | ap_config() | sntp_config()].
@@ -317,7 +322,11 @@ handle_info(
317322
) ->
318323
maybe_ap_sta_ip_assigned_callback(Config, Address),
319324
{noreply, State};
320-
handle_info(_Msg, State) ->
325+
handle_info({Ref, {sntp_sync, TimeVal}} = _Msg, #state{ref = Ref, config = Config} = State) ->
326+
maybe_sntp_sync_callback(Config, TimeVal),
327+
{noreply, State};
328+
handle_info(Msg, State) ->
329+
io:format("Received spurious message ~p~n", [Msg]),
321330
{noreply, State}.
322331

323332
%% @hidden
@@ -352,12 +361,15 @@ get_driver_config(Config) ->
352361

353362
%% @private
354363
maybe_add_nvs_entry(Key, List, NVSKey) ->
355-
case {proplists:get_value(Key, List), esp:nvs_get_binary(atomvm, NVSKey)} of
356-
{undefined, undefined} ->
357-
List;
358-
{undefined, NVSValue} ->
359-
[{Key, NVSValue} | List];
360-
{_Value, _} ->
364+
case proplists:get_value(Key, List) of
365+
undefined ->
366+
case esp:nvs_get_binary(atomvm, NVSKey) of
367+
undefined ->
368+
List;
369+
NVSValue ->
370+
[{Key, NVSValue} | List]
371+
end;
372+
_Value ->
361373
List
362374
end.
363375

@@ -389,6 +401,10 @@ maybe_ap_sta_disconnected_callback(Config, Mac) ->
389401
maybe_ap_sta_ip_assigned_callback(Config, Address) ->
390402
maybe_callback1({sta_ip_assigned, Address}, proplists:get_value(ap, Config)).
391403

404+
%% @private
405+
maybe_sntp_sync_callback(Config, TimeVal) ->
406+
maybe_callback1({synchronized, TimeVal}, proplists:get_value(sntp, Config)).
407+
392408
%% @private
393409
maybe_callback0(_Key, undefined) ->
394410
ok;

src/libAtomVM/term.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ extern "C" {
8686
#define TUPLE_SIZE(elems) ((int) (elems + 1))
8787
#define REFC_BINARY_CONS_OFFET 4
8888

89+
#define TERM_BINARY_SIZE_IS_HEAP(size) ((size) < REFC_BINARY_MIN)
90+
91+
#if TERM_BYTES == 4
92+
#define TERM_BINARY_DATA_SIZE_IN_TERMS(size) \
93+
(TERM_BINARY_SIZE_IS_HEAP(size) ? (((size) + 4 - 1) >> 2) + 1 : TERM_BOXED_REFC_BINARY_SIZE)
94+
#elif TERM_BYTES == 8
95+
#define TERM_BINARY_DATA_SIZE_IN_TERMS(size) \
96+
(TERM_BINARY_SIZE_IS_HEAP(size) ? (((size) + 8 - 1) >> 3) + 1 : TERM_BOXED_REFC_BINARY_SIZE)
97+
#endif
98+
99+
#define TERM_BINARY_HEAP_SIZE(size) \
100+
(TERM_BINARY_DATA_SIZE_IN_TERMS(size) + BINARY_HEADER_SIZE)
101+
89102
#define TERM_DEBUG_ASSERT(...)
90103

91104
#define TERM_FROM_ATOM_INDEX(atom_index) ((atom_index << 6) | 0xB)

0 commit comments

Comments
 (0)