-
Notifications
You must be signed in to change notification settings - Fork 2
/
clock.py
131 lines (109 loc) · 4.42 KB
/
clock.py
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
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class,with
from __future__ import print_function
import time
import re
class Clock:
""" Class representing clock state """
ontime = 0.038 # on pulse width
offtime = 0.022 # minimum off time after pulse
state = 0 # current state of the movement (0..43199)
inverse = False # inversed polarity signal
@staticmethod
def statetohours(state):
""" Converts clock state to a tuple (hour, min, secs) """
state = int(state)
hours = state // 3600
hours = 12 if hours == 0 else hours
mins = (state % 3600) // 60
secs = state % 60
return (hours, mins, secs)
@staticmethod
def hourstostate(hours, mins, secs):
""" Converts tuple (hour, min, secs) to a single number
representing clock state """
return (3600*hours + 60*mins + secs) % 43200
@staticmethod
def statetostr(state):
""" Returns the movement state as a string like 12:34:56 """
return "{:02d}:{:02d}:{:02d}".format(*Clock.statetohours(state))
@staticmethod
def parsestate(statestr):
""" Try to parse movement state from a string as 12:34:56 """
m = re.search("([0-9]+):([0-9]+):([0-9]+)", statestr)
if m:
return Clock.hourstostate(*(int(s) for s in m.groups()))
else:
raise ValueError("movement state not found in "
"string {}".format(statestr))
def __init__(self, clock_signal, polarity_signal,
state=0, inverse_polarity=False):
"""
@param clock_signal GPIO representing
"""
self.CLK = clock_signal
self.POL = polarity_signal
self.state = state
self.inverse = inverse_polarity
def step(self):
"""
Generate one clock step, shift the movement one second ahead.
"""
self.POL.set(self.inverse ^ (self.state & 0x01))
self.CLK.set()
self.state = (self.state + 1) % 43200
time.sleep(self.ontime)
self.CLK.reset()
self.POL.reset()
time.sleep(self.offtime)
def getState(self):
""" Returns current clock state as a string like 12:34:56 """
return Clock.statetostr(self.state)
def setState(self, statestr):
""" Sets clock state from input string """
self.state = Clock.parsestate(statestr)
@property
def stepduration(self):
return self.ontime + self.offtime
def stepstogo(self, desiredstate):
""" Calculates number of steps needed to reach desired state """
# Add 43200 to left side to avoid negative numbers when wrapping over
steps = ((43200+desiredstate) - self.state) % 43200
# In case desired state == current state,
# return full scale instead of 0
return 43200 if steps < 1 else steps
def timetogo(self, desiredstate):
""" Calculates approx. time needed to reach desired state """
# Sum of infinite geometric series with a1 = stepstogo*stepduration
# and q = stepduration
return self.stepduration * \
self.stepstogo(desiredstate) / (1-self.stepduration)
def timetowait(self, desiredstate, comfortsteps=10):
"""
Calculate approx. time to wait until desired state
becomes the current state. A step every comfortsteps seconds
can be added to calm down the user.
"""
timetowait = ((43200+self.state) - int(desiredstate)) % 43200
if comfortsteps > 1:
# This is actually a sum of infinite geometric series
# with a1=timetowait and q=1/comfortsteps
# Sum is therefore a1/(1-q)
timetowait = timetowait*comfortsteps/(comfortsteps-1)
return timetowait
def __str__(self):
return "Clock <{}> Inversed: {}".format(self.getState(), self.inverse)
def __repr__(self):
return "Clock({}, {}, {}, {})".format(self.CLK, self.POL,
self.state, self.inverse)
def test():
clock = Clock(None, None)
print(clock)
clock.setState("13:23:4")
print(clock.getState())
newstate = Clock.parsestate("12:43:04")
print("Time to go: ", clock.timetogo(newstate))
print("Time to wait: ", clock.timetowait(newstate))
print(repr(clock))
if __name__ == "__main__":
test()