-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrtcsync.go
120 lines (95 loc) · 2.86 KB
/
rtcsync.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Author Raido Pahtma
// License MIT
package rtcsync
import "fmt"
import "time"
import "github.com/proactivity-lab/go-loggers"
import "github.com/proactivity-lab/go-moteconnection"
import "github.com/beevik/ntp"
const AMID_RTC = 0x80
const TIME_ANNOUNCEMENT_UNIX = 1
const STARTUP_DELAY = 3 * time.Second
type RTCSyncMsg struct {
Header uint8
Stratum uint8
Nxtime int64
}
func (self *RTCSyncMsg) String() string {
return fmt.Sprintf("ta %d", self.Nxtime)
}
type ClockTimePeriod struct {
Start int
End int
}
type SyncSender struct {
loggers.DIWEloggers
conn moteconnection.MoteConnection
dsp moteconnection.Dispatcher
host string
quiet []ClockTimePeriod
Exit chan bool
}
func NewSyncSender(conn moteconnection.MoteConnection, source moteconnection.AMAddr, group moteconnection.AMGroup, host string) *SyncSender {
ss := new(SyncSender)
ss.InitLoggers()
ss.dsp = moteconnection.NewMessageDispatcher(moteconnection.NewMessage(group, source))
ss.conn = conn
ss.conn.AddDispatcher(ss.dsp)
ss.host = host
ss.Exit = make(chan bool)
return ss
}
func (self *SyncSender) AddQuietPeriod(qp ClockTimePeriod) {
self.Debug.Printf("Quiet period %d-%d\n", qp.Start, qp.End)
self.quiet = append(self.quiet, qp)
}
func (self *SyncSender) AnnounceTime(destination moteconnection.AMAddr, ntpr *ntp.Response, offset int64) {
m := new(RTCSyncMsg)
m.Header = TIME_ANNOUNCEMENT_UNIX
m.Stratum = ntpr.Stratum + 1
m.Nxtime = ntpr.Time.Unix() + offset
msg := self.dsp.NewPacket().(*moteconnection.Message)
msg.SetDestination(destination)
msg.SetType(AMID_RTC)
msg.Payload = moteconnection.SerializePacket(m)
self.Info.Printf("Announce %s->%s %d(%d)\n", msg.Source(), destination, m.Nxtime, offset)
self.conn.Send(msg)
}
func (self *SyncSender) QuietPeriod(t time.Time) bool {
tu := t.UTC()
tss := tu.Hour()*3600 + tu.Minute()*60 + tu.Second()
self.Debug.Printf("Quiet period check: %d\n", tss)
for _, qp := range self.quiet {
if qp.Start <= tss && tss <= qp.End {
return true
}
}
return false
}
func (self *SyncSender) Run(destination moteconnection.AMAddr, period time.Duration, offset int64) {
self.Debug.Printf("run\n")
announcePeriod := 1 * time.Second
for {
select {
case <-self.Exit:
self.Debug.Printf("Exit.\n")
self.conn.Disconnect()
case <-time.After(announcePeriod):
announcePeriod = period
if ntpr, err := ntp.Query(self.host); err == nil {
if err := ntpr.Validate(); err == nil {
self.Debug.Printf("NTP %d stratum %d RTT %s offset %s", ntpr.Time.Unix(), ntpr.Stratum, ntpr.RTT, ntpr.ClockOffset)
if self.QuietPeriod(ntpr.Time) {
self.Info.Printf("Quiet period, not sending time sync.\n")
} else {
self.AnnounceTime(destination, ntpr, offset)
}
} else {
self.Warning.Printf("NTP response validation failed %s", err)
}
} else {
self.Warning.Printf("NTP query failed %s", err)
}
}
}
}