Yet Another WebIOPi+
 All Classes Namespaces Files Functions Variables Macros Pages
dsrtc.py
Go to the documentation of this file.
1 # Copyright 2014 Andreas Riegg - t-h-i-n-x.net
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 # Changelog
16 #
17 # 1.0 2014-06-26 Initial release.
18 # 1.1 2014-08-17 Updated to match v1.1 of Clock implementation
19 #
20 # Config parameters
21 #
22 # - control 8 bit Value of the control register
23 #
24 # Usage remarks
25 #
26 # - All chips have a fixed slave address of 0x68
27 # - Driver uses sequential register access to speed up performance
28 # - Temperature reading from DS3231 is currently not supported
29 # - Setting alarms for DS1337 and DS3231 is currently not supported
30 #
31 
32 from webiopi.utils.types import toint
33 from webiopi.devices.i2c import I2C
34 from webiopi.devices.clock import Clock
35 from webiopi.devices.memory import Memory
36 from webiopi.decorators.rest import request, response
37 from datetime import datetime, date, time
38 
39 
40 class DSclock(I2C, Clock):
41 
42 #---------- Constants and definitions ----------
43 
44  # Common I2C registers for all DSxxxx clock chips
45  SEC = 0x00 # Seconds register coded as 2-digit BCD
46  MIN = 0x01 # Minutes register coded as 2-digit BCD
47  HRS = 0x02 # Hours register coded as 2-digit BCD
48  DOW = 0x03 # Day of week register coded as 1-digit BCD
49  DAY = 0x04 # Day of month register coded as 2-digit BCD
50  MON = 0x05 # Months register coded as 2-digit BCD
51  YRS = 0x06 # Years register coded as 2-digit BCD
52 
53  # Bit masks for common registers for all DSxxxx clock chips
54  SEC_MASK = 0b01111111
55  MIN_MASK = 0b01111111
56  HRS_MASK = 0b00111111
57  DOW_MASK = 0b00000111
58  DAY_MASK = 0b00111111
59  MON_MASK = 0b00011111
60  YRS_MASK = 0b11111111
61 
62 
63 #---------- Class initialization ----------
64 
65  def __init__(self, control):
66  I2C.__init__(self, 0x68)
67  Clock.__init__(self)
68  if control != None:
69  con = toint(control)
70  if not con in range(0, 0xFF + 1):
71  raise ValueError("control value [%d] out of range [%d..%d]" % (con, 0x00, 0xFF))
72  self.__setCon__(con)
73  else:
74  self.__setCon__(self.CON_DEFAULT)
75 
76 
77 #---------- Clock abstraction related methods ----------
78 
79  def __getSec__(self):
80  data = self.readRegister(self.SEC)
81  return self.BcdBits2Int(data & self.SEC_MASK)
82 
83  def __getMin__(self):
84  data = self.readRegister(self.MIN)
85  return self.BcdBits2Int(data & self.MIN_MASK)
86 
87  def __getHrs__(self):
88  data = self.readRegister(self.HRS)
89  return self.BcdBits2Int(data & self.HRS_MASK)
90 
91  def __getDay__(self):
92  data = self.readRegister(self.DAY)
93  return self.BcdBits2Int(data & self.DAY_MASK)
94 
95  def __getMon__(self):
96  data = self.readRegister(self.MON)
97  return self.BcdBits2Int(data & self.MON_MASK)
98 
99  def __getYrs__(self):
100  data = self.readRegister(self.YRS)
101  return 2000 + self.BcdBits2Int(data & self.YRS_MASK)
102 
103  def __getDow__(self):
104  data = self.readRegister(self.DOW)
105  return self.BcdBits2Int(data & self.DOW_MASK)
106 
107  def __setDow__(self, value):
108  self.writeRegister(self.DOW, self.Int2BcdBits(value & self.DOW_MASK))
109 
110 #---------- Clock default re-implementations ----------
111 # Speed up performance by sequential register access
112 
113  def __getDateTime__(self):
114  data = self.readRegisters(self.SEC, 7)
115  second = self.BcdBits2Int(data[0] & self.SEC_MASK)
116  minute = self.BcdBits2Int(data[1] & self.MIN_MASK)
117  hour = self.BcdBits2Int(data[2] & self.HRS_MASK)
118  day = self.BcdBits2Int(data[4] & self.DAY_MASK)
119  month = self.BcdBits2Int(data[5] & self.MON_MASK)
120  year = self.BcdBits2Int(data[6] & self.YRS_MASK) + 2000
121  return datetime(year, month, day, hour, minute, second)
122 
123  def __setDateTime__(self, aDatetime):
124  self.checkYear(aDatetime.year)
125  dow = self.__getDow__() # preserve current dow value
126  data = bytearray(7)
127  data[0] = self.Int2BcdBits(aDatetime.second & self.SEC_MASK)
128  data[1] = self.Int2BcdBits(aDatetime.minute & self.MIN_MASK)
129  data[2] = self.Int2BcdBits(aDatetime.hour & self.HRS_MASK)
130  data[3] = self.Int2BcdBits(dow & self.DOW_MASK)
131  data[4] = self.Int2BcdBits(aDatetime.day & self.DAY_MASK)
132  data[5] = self.Int2BcdBits(aDatetime.month & self.MON_MASK)
133  data[6] = self.Int2BcdBits((aDatetime.year - 2000) & self.YRS_MASK)
134  self.writeRegisters(self.SEC, data)
135 
136  def __getDate__(self):
137  data = self.readRegisters(self.DAY, 3)
138  day = self.BcdBits2Int(data[0] & self.DAY_MASK)
139  month = self.BcdBits2Int(data[1] & self.MON_MASK)
140  year = self.BcdBits2Int(data[2] & self.YRS_MASK) + 2000
141  return date(year, month, day)
142 
143  def __setDate__(self, aDate):
144  self.checkYear(aDate.year)
145  data = bytearray(3)
146  data[0] = self.Int2BcdBits(aDate.day & self.DAY_MASK)
147  data[1] = self.Int2BcdBits(aDate.month & self.MON_MASK)
148  data[2] = self.Int2BcdBits((aDate.year - 2000) & self.YRS_MASK)
149  self.writeRegisters(self.DAY, data)
150 
151  def __getTime__(self):
152  data = self.readRegisters(self.SEC, 3)
153  second = self.BcdBits2Int(data[0] & self.SEC_MASK)
154  minute = self.BcdBits2Int(data[1] & self.MIN_MASK)
155  hour = self.BcdBits2Int(data[2] & self.HRS_MASK)
156  return time(hour, minute, second)
157 
158  def __setTime__(self, aTime):
159  data = bytearray(3)
160  data[0] = self.Int2BcdBits(aTime.second & self.SEC_MASK)
161  data[1] = self.Int2BcdBits(aTime.minute & self.MIN_MASK)
162  data[2] = self.Int2BcdBits(aTime.hour & self.HRS_MASK)
163  self.writeRegisters(self.SEC, data)
164 
165 
166 #---------- Local helpers ----------
167 
168  def __getCon__(self):
169  data = self.readRegister(self.CON)
170  return (data & self.CON_MASK)
171 
172  def __setCon__(self, value):
173  self.writeRegister(self.CON, (value & self.CON_MASK))
174 
175 
177 
178  CON = 0x07 # Control register address
179  RAM = 0x08 # SRAM register address
180 
181  CON_MASK = 0b10010011 # Control register mask
182  CON_DEFAULT = 0b10000011 # Control register default value
183 
184  CH = 0b10000000 # Clock halt bit value/mask
185 
186 
187 #---------- Class initialization ----------
188 
189  def __init__(self, control=None):
190  DSclock.__init__(self, control)
191  Memory.__init__(self, 56)
192  # Clock is stopped by default upon poweron, so start it
193  self.start()
194 
195 
196 #---------- Abstraction framework contracts ----------
197 
198  def __str__(self):
199  return "DS1307"
200 
201  def __family__(self):
202  return [Clock.__family__(self), Memory.__family__(self)]
203 
204 
205 #---------- Clock abstraction related methods ----------
206 
207  def __setSec__(self, value):
208  # Keep CH bit unchanged
209  secValue = self.Int2BcdBits(value)
210  secRegisterData = self.readRegister(self.SEC)
211  self.writeRegister(self.SEC, (secRegisterData & ~self.SEC_MASK) | (secValue & self.SEC_MASK))
212 
213 
214 #---------- Memory abstraction related methods ----------
215 
216  def __readMemoryByte__(self, address):
217  return self.readRegister(self.RAM + address)
218 
219  def __writeMemoryByte__(self, address, value):
220  self.writeRegister(self.RAM + address, value)
221 
222  def __readMemoryWord__(self, address):
223  data = self.readRegisters(self.RAM + address * 2, 2)
224  return (data[0] << 8) + data[1]
225 
226  def __writeMemoryWord__(self, address, value):
227  data = bytearray(2)
228  data[0] = (value >> 8) & 0xFF
229  data[1] = value & 0xFF
230  self.writeRegisters(self.RAM + address * 2, data)
231 
232  def __readMemoryLong__(self, address):
233  data = self.readRegisters(self.RAM + address * 4, 4)
234  return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
235 
236  def __writeMemoryLong__(self, address, value):
237  data = bytearray(4)
238  data[0] = (value >> 24) & 0xFF
239  data[1] = (value >> 16) & 0xFF
240  data[2] = (value >> 8) & 0xFF
241  data[3] = value & 0xFF
242  self.writeRegisters(self.RAM + address * 4, data)
243 
244 
245 #---------- Device features ----------
246 
247  @request("POST", "run/start")
248  def start(self):
249  # Clear CH bit, keep sec value unchanged
250  secRegisterData = self.readRegister(self.SEC)
251  self.writeRegister(self.SEC, (secRegisterData & ~self.CH))
252 
253  @request("POST", "run/stop")
254  def stop(self):
255  # Set CH bit, keep sec value unchanged
256  secRegisterData = self.readRegister(self.SEC)
257  self.writeRegister(self.SEC, (secRegisterData | self.CH))
258 
259 
260 class DS1338(DS1307):
261 
262  CON_MASK = 0b10110011 # Control register mask
263  CON_DEFAULT = 0b10110011 # Control register default value
264 
265 
266 #---------- Class initialization ----------
267 
268  def __init__(self, control=None):
269  DS1307.__init__(self, control)
270 
271 
272 #---------- Abstraction framework contracts ----------
273 
274  def __str__(self):
275  return "DS1338"
276 
277 
279 
280  CON = 0x0E # Control register address
281  CON_MASK = 0b10011111 # Control register mask
282  CON_DEFAULT = 0b00011000 # Control register default value
283  EOSC_ = 0b10000000 # Enable oscillator active low bit value/mask
284 
285 
286 #---------- Class initialization ----------
287 
288  def __init__(self, control=None):
289  DSclock.__init__(self, control)
290 
291 
292 #---------- Abstraction framework contracts ----------
293 
294  def __str__(self):
295  return "DS1337"
296 
297 
298 #---------- Device features ----------
299 
300  @request("POST", "run/start")
301  def start(self):
302  # Clear EOSC_ bit
303  conRegisterData = self.__getCon__()
304  self.__setCon__(conRegisterData & ~self.EOSC_)
305 
306  @request("POST", "run/stop")
307  def stop(self):
308  # Set EOSC_ bit
309  conRegisterData = self.__getCon__()
310  self.__setCon__(conRegisterData | self.EOSC_)
311 
312 
314 
315  CON = 0x0E # Control register address
316  CON_MASK = 0b11011111 # Control register mask
317  CON_DEFAULT = 0b00011100 # Control register default value
318 
319 
320 #---------- Class initialization ----------
321 
322  def __init__(self, control=None):
323  DSclock.__init__(self, control)
324 
325 
326 #---------- Abstraction framework contracts ----------
327 
328  def __str__(self):
329  return "DS3231"
330 
331 
332 
333