tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/examples/net/ntpclient/main.go (about) 1 // This is an example of an NTP client. 2 // 3 // It creates a UDP connection to request the current time and parse the 4 // response from a NTP server. The system time is set to NTP time. 5 6 //go:build ninafw || wioterminal || challenger_rp2040 7 8 package main 9 10 import ( 11 "fmt" 12 "io" 13 "log" 14 "machine" 15 "net" 16 "runtime" 17 "time" 18 19 "tinygo.org/x/drivers/netlink" 20 "tinygo.org/x/drivers/netlink/probe" 21 ) 22 23 var ( 24 ssid string 25 pass string 26 // IP address of the server aka "hub". Replace with your own info. 27 ntpHost string = "0.pool.ntp.org:123" 28 ) 29 30 const NTP_PACKET_SIZE = 48 31 32 var response = make([]byte, NTP_PACKET_SIZE) 33 34 func main() { 35 36 waitSerial() 37 38 link, _ := probe.Probe() 39 40 err := link.NetConnect(&netlink.ConnectParams{ 41 Ssid: ssid, 42 Passphrase: pass, 43 }) 44 if err != nil { 45 log.Fatal(err) 46 } 47 48 conn, err := net.Dial("udp", ntpHost) 49 if err != nil { 50 log.Fatal(err) 51 } 52 53 println("Requesting NTP time...") 54 55 t, err := getCurrentTime(conn) 56 if err != nil { 57 log.Fatal(fmt.Sprintf("Error getting current time: %v", err)) 58 } else { 59 message("NTP time: %v", t) 60 } 61 62 conn.Close() 63 link.NetDisconnect() 64 65 runtime.AdjustTimeOffset(-1 * int64(time.Since(t))) 66 67 for { 68 message("Current time: %v", time.Now()) 69 time.Sleep(time.Minute) 70 } 71 } 72 73 // Wait for user to open serial console 74 func waitSerial() { 75 for !machine.Serial.DTR() { 76 time.Sleep(100 * time.Millisecond) 77 } 78 } 79 80 func getCurrentTime(conn net.Conn) (time.Time, error) { 81 if err := sendNTPpacket(conn); err != nil { 82 return time.Time{}, err 83 } 84 85 n, err := conn.Read(response) 86 if err != nil && err != io.EOF { 87 return time.Time{}, err 88 } 89 if n != NTP_PACKET_SIZE { 90 return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n) 91 } 92 93 return parseNTPpacket(response), nil 94 } 95 96 func sendNTPpacket(conn net.Conn) error { 97 var request = [48]byte{ 98 0xe3, 99 } 100 101 _, err := conn.Write(request[:]) 102 return err 103 } 104 105 func parseNTPpacket(r []byte) time.Time { 106 // the timestamp starts at byte 40 of the received packet and is four bytes, 107 // this is NTP time (seconds since Jan 1 1900): 108 t := uint32(r[40])<<24 | uint32(r[41])<<16 | uint32(r[42])<<8 | uint32(r[43]) 109 const seventyYears = 2208988800 110 return time.Unix(int64(t-seventyYears), 0) 111 } 112 113 func message(format string, args ...interface{}) { 114 println(fmt.Sprintf(format, args...), "\r") 115 }