]>
Commit | Line | Data |
---|---|---|
1 | ## | |
2 | ## This file is part of the libsigrokdecode project. | |
3 | ## | |
4 | ## Copyright (C) 2020 Analog Devices Inc. | |
5 | ## | |
6 | ## This program is free software; you can redistribute it and/or modify | |
7 | ## it under the terms of the GNU General Public License as published by | |
8 | ## the Free Software Foundation; either version 3 of the License, or | |
9 | ## (at your option) any later version. | |
10 | ## | |
11 | ## This program is distributed in the hope that it will be useful, | |
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ## GNU General Public License for more details. | |
15 | ## | |
16 | ## You should have received a copy of the GNU General Public License | |
17 | ## along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | ## | |
19 | ||
20 | import sigrokdecode as srd | |
21 | ||
22 | slave_address = { | |
23 | 0x00: ['GND', 'GND', 'GND', 'G'], | |
24 | 0x01: ['FLOAT', 'FLOAT', 'FLOAT', 'F'], | |
25 | 0x02: ['VCC', 'VCC', 'VCC', 'V'], | |
26 | } | |
27 | ||
28 | commands = { | |
29 | 0x00: ['Write Input Register', 'Write In Reg', 'Wr In Reg', 'WIR'], | |
30 | 0x01: ['Update DAC', 'Update', 'U'], | |
31 | 0x03: ['Write and Power Up DAC', 'Write & Power Up', 'W&PU'], | |
32 | 0x04: ['Power Down DAC', 'Power Down', 'PD'], | |
33 | 0x0F: ['No Operation', 'No Op', 'NO'], | |
34 | } | |
35 | ||
36 | addresses = { | |
37 | 0x00: ['DAC A', 'A'], | |
38 | 0x01: ['DAC B', 'B'], | |
39 | 0x0F: ['All DACs', 'All'], | |
40 | } | |
41 | ||
42 | input_voltage_format = ['%fV', '%fV', '%.6fV', '%.2fV'] | |
43 | ||
44 | class Decoder(srd.Decoder): | |
45 | api_version = 3 | |
46 | id = 'ltc26x7' | |
47 | name = 'LTC26x7' | |
48 | longname = 'Linear Technology LTC26x7' | |
49 | desc = 'Linear Technology LTC26x7 16-/14-/12-bit rail-to-rail DACs.' | |
50 | license = 'gplv2+' | |
51 | inputs = ['i2c'] | |
52 | outputs = [] | |
53 | tags = ['Display'] | |
54 | options = ( | |
55 | {'id': 'part', 'desc': 'Part', 'default': 'ltc26x7', | |
56 | 'values': ('ltc2607', 'ltc2617', 'ltc2627')}, | |
57 | {'id': 'ref', 'desc': 'Reference voltage', 'default': 1.5}, | |
58 | ) | |
59 | annotations = ( | |
60 | ('slave_addr', 'Slave address'), | |
61 | ('command', 'Command'), | |
62 | ('address', 'Address'), | |
63 | ('data', '2 byte data'), | |
64 | ) | |
65 | annotation_rows = ( | |
66 | ('ltc26x7', 'LTC26x7 data', (0, 1, 2, 3)), | |
67 | ) | |
68 | ||
69 | def __init__(self): | |
70 | self.reset() | |
71 | ||
72 | def reset(self): | |
73 | self.state = 'IDLE' | |
74 | self.ss = -1 | |
75 | self.data = 0x00 | |
76 | ||
77 | def start(self): | |
78 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
79 | ||
80 | def convert_ternary_str(self, n): | |
81 | if n == 0: | |
82 | return [0, 0, 0] | |
83 | nums = [] | |
84 | while n: | |
85 | n, r = divmod(n, 3) | |
86 | nums.append(r) | |
87 | while len(nums) < 3: | |
88 | nums.append(0) | |
89 | return list(reversed(nums)) | |
90 | ||
91 | def handle_slave_addr(self, data): | |
92 | if data == 0x73: | |
93 | ann = ['Global address', 'Global addr', 'Glob addr', 'GA'] | |
94 | self.put(self.ss, self.es, self.out_ann, [0, ann]) | |
95 | return | |
96 | ann = ['CA2=%s CA1=%s CA0=%s', '2=%s 1=%s 0=%s', '%s %s %s', '%s %s %s'] | |
97 | addr = 0 | |
98 | for i in range(7): | |
99 | if i in [2, 3]: | |
100 | continue | |
101 | offset = i | |
102 | if i > 3: | |
103 | offset -= 2 | |
104 | mask = 1 << i | |
105 | if data & mask: | |
106 | mask = 1 << offset | |
107 | addr |= mask | |
108 | ||
109 | addr -= 0x04 | |
110 | ternary_values = self.convert_ternary_str(addr) | |
111 | for i in range(len(ann)): | |
112 | ann[i] = ann[i] % (slave_address[ternary_values[0]][i], | |
113 | slave_address[ternary_values[1]][i], | |
114 | slave_address[ternary_values[2]][i]) | |
115 | self.put(self.ss, self.es, self.out_ann, [0, ann]) | |
116 | ||
117 | def handle_cmd_addr(self, data): | |
118 | cmd_val = (data >> 4) & 0x0F | |
119 | dac_val = (data & 0x0F) | |
120 | sm = (self.ss + self.es) // 2 | |
121 | ||
122 | self.put(self.ss, sm, self.out_ann, [1, commands[cmd_val]]) | |
123 | self.put(sm, self.es, self.out_ann, [2, addresses[dac_val]]) | |
124 | ||
125 | def handle_data(self, data): | |
126 | self.data = (self.data << 8) & 0xFF00 | |
127 | self.data += data | |
128 | if self.options['part'] == 'ltc2617': | |
129 | self.data = (self.data >> 2) | |
130 | self.data = (self.options['ref'] * self.data) / 0x3FFF | |
131 | elif self.options['part'] == 'ltc2627': | |
132 | self.data = (self.data >> 4) | |
133 | self.data = (self.options['ref'] * self.data) / 0x0FFF | |
134 | else: | |
135 | self.data = (self.options['ref'] * self.data) / 0xFFFF | |
136 | ann = [] | |
137 | for format in input_voltage_format: | |
138 | ann.append(format % self.data) | |
139 | self.data = 0 | |
140 | ||
141 | self.put(self.ss, self.es, self.out_ann, [3, ann]) | |
142 | ||
143 | def decode(self, ss, es, data): | |
144 | cmd, databyte = data | |
145 | self.es = es | |
146 | ||
147 | # State machine. | |
148 | if self.state == 'IDLE': | |
149 | # Wait for an I²C START condition. | |
150 | if cmd != 'START': | |
151 | return | |
152 | self.state = 'GET SLAVE ADDR' | |
153 | elif self.state == 'GET SLAVE ADDR': | |
154 | # Wait for an address write operation. | |
155 | if cmd != 'ADDRESS WRITE': | |
156 | return | |
157 | self.ss = ss | |
158 | self.handle_slave_addr(databyte) | |
159 | self.ss = -1 | |
160 | self.state = 'GET CMD ADDR' | |
161 | elif self.state == 'GET CMD ADDR': | |
162 | if cmd != 'DATA WRITE': | |
163 | return | |
164 | self.ss = ss | |
165 | self.handle_cmd_addr(databyte) | |
166 | self.ss = -1 | |
167 | self.state = 'WRITE DATA' | |
168 | elif self.state == 'WRITE DATA': | |
169 | if cmd == 'DATA WRITE': | |
170 | if self.ss == -1: | |
171 | self.ss = ss | |
172 | self.data = databyte | |
173 | return | |
174 | self.handle_data(databyte) | |
175 | self.ss = -1 | |
176 | elif cmd == 'STOP': | |
177 | self.state = 'IDLE' | |
178 | else: | |
179 | return |