@@ -17,82 +17,140 @@ Supported SNTP protocol versions:
17
17
18
18
-----------------
19
19
20
- https://docs.rs/sntpc
20
+ More information about this crate can be found in the [ crate documentation ] ( https://docs.rs/sntpc )
21
21
22
- ### Installation
22
+ ### Usage example
23
23
24
- ----------------
25
-
26
- This crate works with Cargo and is on
27
- [ crates.io] ( https://crates.io/crates/sntpc ) . Add it to your ` Cargo.toml `
28
- like so:
24
+ - dependency for the app
29
25
30
26
``` toml
31
27
[dependencies ]
32
- sntpc = " 0.4.0 "
28
+ sntpc = { version = " 0.5 " , features = [ " sync " ] }
33
29
```
34
30
35
- By calling the ` get_time() ` method and providing a proper NTP pool or server you
36
- should get a valid synchronization timestamp:
31
+ - application code
37
32
38
33
``` rust
39
- use std :: net :: UdpSocket ;
34
+ use sntpc :: {sync :: get_time, NtpContext , StdTimestampGen };
35
+
36
+ use std :: net :: {SocketAddr , ToSocketAddrs , UdpSocket };
37
+ use std :: thread;
40
38
use std :: time :: Duration ;
41
39
40
+ #[allow(dead_code)]
41
+ const POOL_NTP_ADDR : & str = " pool.ntp.org:123" ;
42
+ #[allow(dead_code)]
43
+ const GOOGLE_NTP_ADDR : & str = " time.google.com:123" ;
44
+
42
45
fn main () {
46
+ #[cfg(feature = " log" )]
47
+ if cfg! (debug_assertions ) {
48
+ simple_logger :: init_with_level (log :: Level :: Trace ). unwrap ();
49
+ } else {
50
+ simple_logger :: init_with_level (log :: Level :: Info ). unwrap ();
51
+ }
52
+
43
53
let socket =
44
54
UdpSocket :: bind (" 0.0.0.0:0" ). expect (" Unable to crate UDP socket" );
45
55
socket
46
56
. set_read_timeout (Some (Duration :: from_secs (2 )))
47
57
. expect (" Unable to set UDP socket read timeout" );
48
- let result = sntpc :: simple_get_time (" time.google.com:123" , & socket );
49
- match result {
50
- Ok (time ) => {
51
- println! (" Got time: {}.{}" , time . sec (), sntpc :: fraction_to_milliseconds (time . sec_fraction ()));
58
+
59
+ for addr in POOL_NTP_ADDR . to_socket_addrs (). unwrap () {
60
+ let ntp_context = NtpContext :: new (StdTimestampGen :: default ());
61
+ let result = get_time (addr , & socket , ntp_context );
62
+
63
+ match result {
64
+ Ok (time ) => {
65
+ assert_ne! (time . sec (), 0 );
66
+ let seconds = time . sec ();
67
+ let microseconds = u64 :: from (time . sec_fraction ()) * 1_000_000
68
+ / u64 :: from (u32 :: MAX );
69
+ println! (" Got time from [{POOL_NTP_ADDR}] {addr}: {seconds}.{microseconds}" );
70
+
71
+ break ;
72
+ }
73
+ Err (err ) => println! (" Err: {err:?}" ),
52
74
}
53
- Err (err ) => println! (" Err: {:?}" , err ),
75
+
76
+ thread :: sleep (Duration :: new (2 , 0 ));
54
77
}
55
78
}
56
79
```
57
80
81
+ You can find this [ example] ( examples/simple-request ) as well as other example projects in the
82
+ [ example directory] ( examples ) .
83
+
58
84
## ` no_std ` support
59
85
60
86
-------------------
61
87
62
- Currently, there are basic ` no_std ` support available, thanks to [ ` no-std-net ` ] ( https://crates.io/crates/no-std-net )
63
- crate. There is an example available on how to use [ ` smoltcp ` ] [ smoltcp ] stack and that should provide
88
+ There is an example available on how to use [ ` smoltcp ` ] ( examples/smoltcp-request ) stack and that should provide
64
89
general idea on how to bootstrap ` no_std ` networking and timestamping tools for ` sntpc ` library usage
65
90
66
91
## ` async ` support
67
92
68
93
-------------------
69
94
70
- Feature ` async_tokio ` allows to use crate together with [ tokio] ( https://docs.rs/tokio/latest/tokio/ ) .
71
- Example available in the [ repository] ( https://github.com/vpetrigo/sntpc ) .
95
+ Starting version ` 0.5 ` the default interface is ` async ` . If you want to use synchronous interface, read about ` sync `
96
+ feature below.
97
+
98
+ ` tokio ` example: [ ` examples/tokio ` ] ( examples/tokio )
72
99
73
100
There is also ` no_std ` support with feature ` async ` , but it requires Rust >= ` 1.75-nightly ` version.
74
101
The example can be found in [ separate repository] ( https://github.com/vpikulik/sntpc_embassy ) .
75
102
76
- # Examples
103
+ ## ` sync ` support
104
+
105
+ -------------------
106
+
107
+ ` sntpc ` crate is ` async ` by default, since most of the frameworks (I have seen) for embedded systems utilize
108
+ asynchronous approach, e.g.:
109
+
110
+ - [ RTIC] ( https://github.com/rtic-rs/rtic )
111
+ - [ embassy] ( https://github.com/embassy-rs/embassy )
112
+
113
+ If you need fully synchronous interface it is available in the ` sntpc::sync ` submodule and respective ` sync ` -feature
114
+ enabled. In the case someone needs a synchronous socket support the currently async ` NtpUdpSocket ` trait can be
115
+ implemented in a fully synchronous manner. This is an example for the ` std::net::UdpSocket ` that is available in the
116
+ crate:
77
117
78
- ----------
118
+ ``` rust
119
+ #[cfg(feature = " std" )]
120
+ impl NtpUdpSocket for UdpSocket {
121
+ async fn send_to (& self , buf : & [u8 ], addr : SocketAddr ) -> Result <usize > {
122
+ match self . send_to (buf , addr ) {
123
+ Ok (usize ) => Ok (usize ),
124
+ Err (_ ) => Err (Error :: Network ),
125
+ }
126
+ }
127
+
128
+ async fn recv_from (& self , buf : & mut [u8 ]) -> Result <(usize , SocketAddr )> {
129
+ match self . recv_from (buf ) {
130
+ Ok ((size , addr )) => Ok ((size , addr )),
131
+ Err (_ ) => Err (Error :: Network ),
132
+ }
133
+ }
134
+ }
135
+ ```
79
136
80
- You can find several examples that shows how to use the library in details under [ examples/ ] folder.
81
- Currently, there are examples that show:
137
+ As you can see, you may implement everything as synchronous, ` sntpc ` synchronous interface handles ` async ` -like stuff
138
+ internally.
82
139
83
- - usage of SNTP library in ` std ` environment
84
- - usage of SNTP library with [ ` smoltcp ` ] [ smoltcp ] TCP/IP stack. Some ` std ` dependencies
85
- required only due to smoltcp available interfaces
140
+ That approach also allows to avoid issues with [ ` maybe_async ` ] ( https://docs.rs/maybe-async/latest/maybe_async/ ) when the
141
+ sync/async feature [ violates Cargo requirements] ( https://doc.rust-lang.org/cargo/reference/features.html ) :
142
+ > That is, enabling a feature should not disable functionality, and it should usually be safe to enable any combination
143
+ > of features.
86
144
87
- [ smoltcp ] : https://github.com/smoltcp-rs/smoltcp
145
+ Small overhead introduced by creating an executor should be negligible.
88
146
89
147
# Contribution
90
148
91
149
--------------
92
150
93
151
Contributions are always welcome! If you have an idea, it's best to float it by me before working on it to ensure no
94
152
effort is wasted. If there's already an open issue for it, knock yourself out. See the
95
- [ ** contributing section** ] ( https://github.com/vpetrigo/sntpc/blob/master/ CONTRIBUTING.md) for additional details
153
+ [ ** contributing section** ] ( CONTRIBUTING.md ) for additional details
96
154
97
155
## Thanks
98
156
@@ -105,6 +163,8 @@ effort is wasted. If there's already an open issue for it, knock yourself out. S
105
163
5 . [ Vitali Pikulik] ( https://github.com/vpikulik ) : for adding ` async ` support
106
164
6 . [ tsingwong] ( https://github.com/tsingwong ) : for fixing invalid link in the ` README.md `
107
165
7 . [ Robert Bastian] ( https://github.com/robertbastian ) : for fixing the overflow issue in the ` calculate_offset `
166
+ 8 . [ oleid] ( https://github.com/oleid ) : for bringing ` embassy ` socket support
167
+ 9 . [ Damian Peckett] ( https://github.com/dpeckett ) : for adding ` defmt ` support and elaborating on ` embassy ` example
108
168
109
169
Really appreciate all your efforts! Please [ let me know] ( mailto:vladimir.petrigo@gmail.com ) if I forgot someone.
110
170
0 commit comments