Yet Another WebIOPi+
 All Classes Namespaces Files Functions Variables Macros Pages
mcprtc.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-25 Initial release.
18 # 1.1 2014-08-27 Updated to match v1.1 of Clock implementation
19 # Added seq register access for __get ...
20 #
21 # Config parameters
22 #
23 # - control 8 bit Value of the control register
24 #
25 # Usage remarks
26 #
27 # - The chip has a fixed slave address of 0x6F
28 # - Setting alarms is currently not supported
29 #
30 # - TBD writing security for 59 sec timeslot
31 #
32 # Implementation remarks
33 #
34 # - The driver has high similarity with the dsrtc one any may be merged
35 # with it (or inherit from DSclock) sometime in future
36 #
37 
38 from webiopi.utils.types import toint
39 from webiopi.devices.i2c import I2C
40 from webiopi.devices.clock import Clock
41 from webiopi.devices.memory import Memory
42 from webiopi.decorators.rest import request, response
43 from datetime import datetime, date, time
44 
45 
47 
48 #---------- Constants and definitions ----------
49 
50  # Common I2C registers for all DSxxxx clock chips
51  SEC = 0x00 # Seconds register coded as 2-digit BCD
52  MIN = 0x01 # Minutes register coded as 2-digit BCD
53  HRS = 0x02 # Hours register coded as 2-digit BCD
54  DOW = 0x03 # Day of week register coded as 1-digit BCD
55  DAY = 0x04 # Day of month register coded as 2-digit BCD
56  MON = 0x05 # Months register coded as 2-digit BCD
57  YRS = 0x06 # Years register coded as 2-digit BCD
58  CON = 0x07 # Control register address
59  RAM = 0x20 # SRAM register address
60 
61  # Bit masks for registers
62  SEC_MASK = 0b01111111
63  MIN_MASK = 0b01111111
64  HRS_MASK = 0b00111111
65  DOW_MASK = 0b00000111
66  DAY_MASK = 0b00111111
67  MON_MASK = 0b00011111
68  YRS_MASK = 0b11111111
69 
70  CON_MASK = 0b10010011 # Control register mask
71  CON_DEFAULT = 0b00000011 # Control register default value
72 
73  ST = 0b10000000 # Start oscillator bit value/mask
74 
75 #---------- Class initialisation ----------
76 
77  def __init__(self, control=None):
78  I2C.__init__(self, 0x6F)
79  Clock.__init__(self)
80  Memory.__init__(self, 64)
81  if control != None:
82  con = toint(control)
83  if not con in range(0, 0xFF + 1):
84  raise ValueError("control value %d out of range [%d..%d]" % (con, 0x00, 0xFF))
85  self.__setCon__(con)
86  else:
87  self.__setCon__(self.CON_DEFAULT)
88 
89  # Clock is stopped by default upon poweron, so start it
90  self.start()
91 
92 
93 #---------- Abstraction framework contracts ----------
94 
95  def __str__(self):
96  return "MCP7940"
97 
98  def __family__(self):
99  return [Clock.__family__(self), Memory.__family__(self)]
100 
101 
102 #---------- Clock abstraction related methods ----------
103 
104  def __getSec__(self):
105  data = self.readRegister(self.SEC)
106  return self.BcdBits2Int(data & self.SEC_MASK)
107 
108  def __setSec__(self, value):
109  # Keep ST bit unchanged
110  secValue = self.Int2BcdBits(value)
111  secRegisterData = self.readRegister(self.SEC)
112  self.writeRegister(self.SEC, (secRegisterData & ~self.SEC_MASK) | (secValue & self.SEC_MASK))
113 
114  def __getMin__(self):
115  data = self.readRegister(self.MIN)
116  return self.BcdBits2Int(data & self.MIN_MASK)
117 
118  def __setMin__(self, value):
119  self.writeRegister(self.MIN, self.Int2BcdBits(value & self.MIN_MASK))
120 
121  def __getHrs__(self):
122  data = self.readRegister(self.HRS)
123  return self.BcdBits2Int(data & self.HRS_MASK)
124 
125  def __setHrs__(self, value):
126  # Keep 12/24 bit unchanged
127  hrsValue = self.Int2BcdBits(value)
128  hrsRegisterData = self.readRegister(self.HRS)
129  self.writeRegister(self.HRS, (hrsRegisterData & ~self.HRS_MASK) | (hrsValue & self.HRS_MASK))
130 
131  def __getDay__(self):
132  data = self.readRegister(self.DAY)
133  return self.BcdBits2Int(data & self.DAY_MASK)
134 
135  def __setDay__(self, value):
136  self.writeRegister(self.DAY, self.Int2BcdBits(value & self.DAY_MASK))
137 
138  def __getMon__(self):
139  data = self.readRegister(self.MON)
140  return self.BcdBits2Int(data & self.MON_MASK)
141 
142  def __setMon__(self, value):
143  # Keep LP bit unchanged
144  monValue = self.Int2BcdBits(value)
145  monRegisterData = self.readRegister(self.MON)
146  self.writeRegister(self.MON, (monRegisterData & ~self.MON_MASK) | (monValue & self.MON_MASK))
147 
148  def __getYrs__(self):
149  data = self.readRegister(self.YRS)
150  return 2000 + self.BcdBits2Int(data & self.YRS_MASK)
151 
152  def __setYrs__(self, value):
153  self.writeRegister(self.YRS, self.Int2BcdBits((value - 2000) & self.YRS_MASK))
154 
155  def __getDow__(self):
156  data = self.readRegister(self.DOW)
157  return self.BcdBits2Int(data & self.DOW_MASK)
158 
159  def __setDow__(self, value):
160  # Keep control bits unchanged
161  dowValue = self.Int2BcdBits(value)
162  dowRegisterData = self.readRegister(self.DOW)
163  self.writeRegister(self.DOW, (dowRegisterData & ~self.DOW_MASK) | (dowValue & self.DOW_MASK))
164 
165 #---------- Clock default re-implementations ----------
166 # Speed up performance by sequential register access
167 # Only provided for __getxxx__() methods as presevering bits of time
168 # registers within __setxxx__() methods would need too much reads before
169 # which will degrade speed improvement a lot. And, setting values of
170 # RTC chips occurs very seldom anyway.
171 
172  def __getDateTime__(self):
173  data = self.readRegisters(self.SEC, 7)
174  second = self.BcdBits2Int(data[0] & self.SEC_MASK)
175  minute = self.BcdBits2Int(data[1] & self.MIN_MASK)
176  hour = self.BcdBits2Int(data[2] & self.HRS_MASK)
177  day = self.BcdBits2Int(data[4] & self.DAY_MASK)
178  month = self.BcdBits2Int(data[5] & self.MON_MASK)
179  year = self.BcdBits2Int(data[6] & self.YRS_MASK) + 2000
180  return datetime(year, month, day, hour, minute, second)
181 
182  def __getDate__(self):
183  data = self.readRegisters(self.DAY, 3)
184  day = self.BcdBits2Int(data[0] & self.DAY_MASK)
185  month = self.BcdBits2Int(data[1] & self.MON_MASK)
186  year = self.BcdBits2Int(data[2] & self.YRS_MASK) + 2000
187  return date(year, month, day)
188 
189  def __getTime__(self):
190  data = self.readRegisters(self.SEC, 3)
191  second = self.BcdBits2Int(data[0] & self.SEC_MASK)
192  minute = self.BcdBits2Int(data[1] & self.MIN_MASK)
193  hour = self.BcdBits2Int(data[2] & self.HRS_MASK)
194  return time(hour, minute, second)
195 
196 
197 #---------- Memory abstraction related methods ----------
198 
199  def __readMemoryByte__(self, address):
200  return self.readRegister(self.RAM + address)
201 
202  def __writeMemoryByte__(self, address, value):
203  self.writeRegister(self.RAM + address, value)
204 
205  def __readMemoryWord__(self, address):
206  data = self.readRegisters(self.RAM + address * 2, 2)
207  return (data[0] << 8) + data[1]
208 
209  def __writeMemoryWord__(self, address, value):
210  data = bytearray(2)
211  data[0] = (value >> 8) & 0xFF
212  data[1] = value & 0xFF
213  self.writeRegisters(self.RAM + address * 2, data)
214 
215  def __readMemoryLong__(self, address):
216  data = self.readRegisters(self.RAM + address * 4, 4)
217  return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
218 
219  def __writeMemoryLong__(self, address, value):
220  data = bytearray(4)
221  data[0] = (value >> 24) & 0xFF
222  data[1] = (value >> 16) & 0xFF
223  data[2] = (value >> 8) & 0xFF
224  data[3] = value & 0xFF
225  self.writeRegisters(self.RAM + address * 4, data)
226 
227 
228 #---------- Device features ----------
229 
230  @request("POST", "run/start")
231  def start(self):
232  # Set ST bit, keep sec value unchanged
233  secRegisterData = self.readRegister(self.SEC)
234  self.writeRegister(self.SEC, (secRegisterData | self.ST))
235 
236  @request("POST", "run/stop")
237  def stop(self):
238  # Clear ST bit, keep sec value unchanged
239  secRegisterData = self.readRegister(self.SEC)
240  self.writeRegister(self.SEC, (secRegisterData & ~self.ST))
241 
242 #---------- Local helpers ----------
243 
244  def __getCon__(self):
245  data = self.readRegister(self.CON)
246  return (data & self.CON_MASK)
247 
248  def __setCon__(self, value):
249  self.writeRegister(self.CON, (value & self.CON_MASK))