2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2012-2014 Uwe Hermann <uwe@hermann-uwe.de>
5 ## Copyright (C) 2013 Matt Ranostay <mranostay@gmail.com>
7 ## This program is free software; you can redistribute it and/or modify
8 ## it under the terms of the GNU General Public License as published by
9 ## the Free Software Foundation; either version 2 of the License, or
10 ## (at your option) any later version.
12 ## This program is distributed in the hope that it will be useful,
13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ## GNU General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with this program; if not, write to the Free Software
19 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 import sigrokdecode as srd
26 'Sunday', 'Monday', 'Tuesday', 'Wednesday',
27 'Thursday', 'Friday', 'Saturday',
31 'Seconds', 'Minutes', 'Hours', 'Day', 'Date', 'Month', 'Year',
36 'Clock halt', 'Seconds', 'Reserved', 'Minutes', '12/24 hours', 'AM/PM',
37 'Hours', 'Day', 'Date', 'Month', 'Year', 'OUT', 'SQWE', 'RS', 'RAM',
41 l = [('reg-' + r.lower(), r + ' register') for r in regs]
42 l += [('bit-' + re.sub('\/| ', '-', b).lower(), b + ' bit') for b in bits]
45 # Return the specified BCD number (max. 8 bits) as integer.
47 return (b & 0x0f) + ((b >> 4) * 10)
49 class Decoder(srd.Decoder):
53 longname = 'Dallas DS1307'
54 desc = 'Realtime clock module protocol.'
58 annotations = regs_and_bits() + (
59 ('read-datetime', 'Read date/time'),
60 ('write-datetime', 'Write date/time'),
61 ('reg-read', 'Register read'),
62 ('reg-write', 'Register write'),
65 ('bits', 'Bits', tuple(range(9, 24))),
66 ('regs', 'Registers', tuple(range(9))),
67 ('date-time', 'Date/time', (24, 25, 26, 27)),
70 def __init__(self, **kwargs):
82 self.out_ann = self.register(srd.OUTPUT_ANN)
85 self.put(self.ss, self.es, self.out_ann, data)
87 def putd(self, bit1, bit2, data):
88 self.put(self.bits[bit1][1], self.bits[bit2][2], self.out_ann, data)
91 self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann,
92 [11, ['Reserved bit', 'Reserved', 'Rsvd', 'R']])
94 def handle_reg_0x00(self, b): # Seconds (0-59) / Clock halt bit
95 self.putd(7, 0, [0, ['Seconds', 'Sec', 'S']])
96 ch = 1 if (b & (1 << 7)) else 0
97 self.putd(7, 7, [9, ['Clock halt: %d' % ch, 'Clk hlt: %d' % ch,
98 'CH: %d' % ch, 'CH']])
99 s = self.seconds = bcd2int(b & 0x7f)
100 self.putd(6, 0, [10, ['Second: %d' % s, 'Sec: %d' % s, 'S: %d' % s, 'S']])
102 def handle_reg_0x01(self, b): # Minutes (0-59)
103 self.putd(7, 0, [1, ['Minutes', 'Min', 'M']])
105 m = self.minutes = bcd2int(b & 0x7f)
106 self.putd(6, 0, [12, ['Minute: %d' % m, 'Min: %d' % m, 'M: %d' % m, 'M']])
108 def handle_reg_0x02(self, b): # Hours (1-12+AM/PM or 0-23)
109 self.putd(7, 0, [2, ['Hours', 'H']])
111 ampm_mode = True if (b & (1 << 6)) else False
113 self.putd(6, 6, [13, ['12-hour mode', '12h mode', '12h']])
114 a = 'AM' if (b & (1 << 6)) else 'PM'
115 self.putd(5, 5, [14, [a, a[0]]])
116 h = self.hours = bcd2int(b & 0x1f)
117 self.putd(4, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']])
119 self.putd(6, 6, [13, ['24-hour mode', '24h mode', '24h']])
120 h = self.hours = bcd2int(b & 0x3f)
121 self.putd(5, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']])
123 def handle_reg_0x03(self, b): # Day / day of week (1-7)
124 self.putd(7, 0, [3, ['Day of week', 'Day', 'D']])
125 for i in (7, 6, 5, 4, 3):
127 w = self.days = bcd2int(b & 0x07)
128 ws = days_of_week[self.days - 1]
129 self.putd(2, 0, [16, ['Weekday: %s' % ws, 'WD: %s' % ws, 'WD', 'W']])
131 def handle_reg_0x04(self, b): # Date (1-31)
132 self.putd(7, 0, [4, ['Date', 'D']])
135 d = self.date = bcd2int(b & 0x3f)
136 self.putd(5, 0, [17, ['Date: %d' % d, 'D: %d' % d, 'D']])
138 def handle_reg_0x05(self, b): # Month (1-12)
139 self.putd(7, 0, [5, ['Month', 'Mon', 'M']])
142 m = self.months = bcd2int(b & 0x1f)
143 self.putd(4, 0, [18, ['Month: %d' % m, 'Mon: %d' % m, 'M: %d' % m, 'M']])
145 def handle_reg_0x06(self, b): # Year (0-99)
146 self.putd(7, 0, [6, ['Year', 'Y']])
147 y = self.years = bcd2int(b & 0xff)
149 self.putd(7, 0, [19, ['Year: %d' % y, 'Y: %d' % y, 'Y']])
151 def handle_reg_0x07(self, b): # Control Register
154 def decode(self, ss, es, data):
157 # Collect the 'BITS' packet, then return. The next packet is
158 # guaranteed to belong to these bits we just stored.
163 # Store the start/end samples of this I²C packet.
164 self.ss, self.es = ss, es
167 if self.state == 'IDLE':
168 # Wait for an I²C START condition.
171 self.state = 'GET SLAVE ADDR'
172 self.block_start_sample = ss
173 elif self.state == 'GET SLAVE ADDR':
174 # Wait for an address write operation.
175 # TODO: We should only handle packets to the RTC slave (0x68).
176 if cmd != 'ADDRESS WRITE':
178 self.state = 'GET REG ADDR'
179 elif self.state == 'GET REG ADDR':
180 # Wait for a data write (master selects the slave register).
181 if cmd != 'DATA WRITE':
184 self.state = 'WRITE RTC REGS'
185 elif self.state == 'WRITE RTC REGS':
186 # If we see a Repeated Start here, it's probably an RTC read.
187 if cmd == 'START REPEAT':
188 self.state = 'READ RTC REGS'
190 # Otherwise: Get data bytes until a STOP condition occurs.
191 if cmd == 'DATA WRITE':
192 handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
195 # TODO: Check for NACK!
197 # TODO: Handle read/write of only parts of these items.
198 d = '%s, %02d.%02d.%4d %02d:%02d:%02d' % (
199 days_of_week[self.days - 1], self.date, self.months,
200 self.years, self.hours, self.minutes, self.seconds)
201 self.put(self.block_start_sample, es, self.out_ann,
202 [25, ['Written date/time: %s' % d]])
206 elif self.state == 'READ RTC REGS':
207 # Wait for an address read operation.
208 # TODO: We should only handle packets to the RTC slave (0x68).
209 if cmd == 'ADDRESS READ':
210 self.state = 'READ RTC REGS2'
214 elif self.state == 'READ RTC REGS2':
215 if cmd == 'DATA READ':
216 handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
219 # TODO: Check for NACK!
221 d = '%s, %02d.%02d.%4d %02d:%02d:%02d' % (
222 days_of_week[self.days - 1], self.date, self.months,
223 self.years, self.hours, self.minutes, self.seconds)
224 self.put(self.block_start_sample, es, self.out_ann,
225 [24, ['Read date/time: %s' % d]])