]> sigrok.org Git - libsigrokdecode.git/blame - decoders/dali/pd.py
avr_isp: Add more parts
[libsigrokdecode.git] / decoders / dali / pd.py
CommitLineData
b26c713b
JS
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2015 Jeremy Swanson <jeremy@rakocontrols.com>
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 2 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
20import sigrokdecode as srd
21from .lists import *
22
23class SamplerateError(Exception):
24 pass
25
26class Decoder(srd.Decoder):
02760d3b 27 api_version = 3
b26c713b
JS
28 id = 'dali'
29 name = 'DALI'
30 longname = 'Digital Addressable Lighting Interface'
2787cf2a 31 desc = 'Digital Addressable Lighting Interface (DALI) protocol.'
b26c713b
JS
32 license = 'gplv2+'
33 inputs = ['logic']
6cbba91f 34 outputs = []
d6d8a8a4 35 tags = ['Embedded/industrial', 'Lighting']
b26c713b
JS
36 channels = (
37 {'id': 'dali', 'name': 'DALI', 'desc': 'DALI data line'},
38 )
39 options = (
40 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
41 'values': ('active-low', 'active-high')},
42 )
43 annotations = (
44 ('bit', 'Bit'),
e144452b 45 ('startbit', 'Start bit'),
b26c713b
JS
46 ('sbit', 'Select bit'),
47 ('ybit', 'Individual or group'),
48 ('address', 'Address'),
49 ('command', 'Command'),
50 ('reply', 'Reply data'),
51 ('raw', 'Raw data'),
52 )
53 annotation_rows = (
54 ('bits', 'Bits', (0,)),
e144452b 55 ('raw-data', 'Raw data', (7,)),
37133b0a 56 ('fields', 'Fields', (1, 2, 3, 4, 5, 6)),
b26c713b
JS
57 )
58
59 def __init__(self):
10aeb8ea
GS
60 self.reset()
61
62 def reset(self):
b26c713b 63 self.samplerate = None
b26c713b
JS
64 self.edges, self.bits, self.ss_es_bits = [], [], []
65 self.state = 'IDLE'
44789507 66 self.dev_type = None
b26c713b
JS
67
68 def start(self):
69 self.out_ann = self.register(srd.OUTPUT_ANN)
a8933728 70 self.old_dali = 1 if self.options['polarity'] == 'active-low' else 0
b26c713b
JS
71
72 def metadata(self, key, value):
73 if key == srd.SRD_CONF_SAMPLERATE:
74 self.samplerate = value
75 # One bit: 833.33us (one half low, one half high).
76 # This is how may samples are in 1TE.
77 self.halfbit = int((self.samplerate * 0.0008333) / 2.0)
78
79 def putb(self, bit1, bit2, data):
80 ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1]
81 self.put(ss, es, self.out_ann, data)
82
83 def handle_bits(self, length):
84 a, c, f, g, b = 0, 0, 0, 0, self.bits
85 # Individual raw bits.
86 for i in range(length):
87 if i == 0:
88 ss = max(0, self.bits[0][0])
89 else:
90 ss = self.ss_es_bits[i - 1][1]
91 es = self.bits[i][0] + (self.halfbit * 2)
92 self.ss_es_bits.append([ss, es])
93 self.putb(i, i, [0, ['%d' % self.bits[i][1]]])
94 # Bits[0:0]: Startbit
95 s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S']
96 self.putb(0, 0, [1, s])
97 self.putb(0, 0, [7, s])
98 # Bits[1:8]
99 for i in range(8):
100 f |= (b[1 + i][1] << (7 - i))
101 if length == 9: # BACKWARD Frame
102 s = ['Reply: %02X' % f, 'Rply: %02X' % f,
103 'Rep: %02X' % f, 'R: %02X' % f, 'R']
104 self.putb(1, 8, [7, s])
105 s = ['Reply: %d' % f, 'Rply: %d' % f,
106 'Rep: %d' % f, 'R: %d' % f, 'R']
107 self.putb(1, 8, [6, s])
108 return
109
110 # FORWARD FRAME
111 # Bits[9:16]: Command/data (MSB-first)
112 for i in range(8):
113 c |= (b[9 + i][1] << (7 - i))
114 # Raw output
115 s = ['Raw data: %02X' % f, 'Raw: %02X' % f,
116 'Raw: %02X' % f, 'R: %02X' % f, 'R']
117 self.putb(1, 8, [7, s])
118 s = ['Raw data: %02X' % c, 'Raw: %02X' % c,
119 'Raw: %02X' % c, 'R: %02X' % c, 'R']
120 self.putb(9, 16, [7, s])
121
122 # Bits[8:8]: Select bit
123 # s = ['Selectbit: %d' % b[8][1], 'SEL: %d' % b[8][1], 'SEL', 'SE', 'S']
124 if b[8][1] == 1:
125 s = ['Command', 'Comd', 'COM', 'CO', 'C']
126 else:
127 s = ['Arc Power Level', 'Arc Pwr', 'ARC', 'AC', 'A']
128 self.putb(8, 8, [1, s])
129
130 # f &= 254 # Clear the select bit.
131 if f >= 254: # BROADCAST
132 s = ['BROADCAST', 'Brdcast', 'BC', 'B', 'B']
133 self.putb(1, 7, [5, s])
134 elif f >= 160: # Extended command 0b10100000
135 if f == 0xC1: # DALI_ENABLE_DEVICE_TYPE_X
44789507
UH
136 self.dev_type = -1
137 x = extended_commands.get(f, ['Unknown', 'Unk'])
b26c713b
JS
138 s = ['Extended Command: %02X (%s)' % (f, x[0]),
139 'XC: %02X (%s)' % (f, x[1]),
140 'XC: %02X' % f, 'X: %02X' % f, 'X']
141 self.putb(1, 8, [5, s])
142 elif f >= 128: # Group
143 # Bits[1:1]: Ybit
144 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
145 self.putb(1, 1, [3, s])
146 g = (f & 127) >> 1
147 s = ['Group address: %d' % g, 'Group: %d' % g,
148 'GP: %d' % g, 'G: %d' % g, 'G']
149 self.putb(2,7, [4, s])
150 else: # Short address
151 # Bits[1:1]: Ybit
152 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
153 self.putb(1, 1, [3, s])
154 a = f >> 1
b26c713b
JS
155 s = ['Short address: %d' % a, 'Addr: %d' % a,
156 'Addr: %d' % a, 'A: %d' % a, 'A']
157 self.putb(2, 7, [4, s])
158
159 # Bits[9:16]: Command/data (MSB-first)
160 if f >= 160 and f < 254:
44789507
UH
161 if self.dev_type == -1:
162 self.dev_type = c
b26c713b
JS
163 s = ['Type: %d' % c, 'Typ: %d' % c,
164 'Typ: %d' % c, 'T: %d' % c, 'D']
165 else:
44789507 166 self.dev_type = None
b26c713b
JS
167 s = ['Data: %d' % c, 'Dat: %d' % c,
168 'Dat: %d' % c, 'D: %d' % c, 'D']
169 elif b[8][1] == 1:
170 un = c & 0xF0
171 ln = c & 0x0F
172 if un == 0x10: # Set scene command
173 x = ['Recall Scene %d' % ln, 'SC %d' % ln]
174 elif un == 0x40:
175 x = ['Store DTR as Scene %d' % ln, 'SC %d = DTR' % ln]
176 elif un == 0x50:
177 x = ['Delete Scene %d' % ln, 'DEL SC %d' % ln]
178 elif un == 0x60:
179 x = ['Add to Group %d' % ln, 'Grp %d Add' % ln]
180 elif un == 0x70:
181 x = ['Remove from Group %d' % ln, 'Grp %d Del' % ln]
182 elif un == 0xB0:
183 x = ['Query Scene %d Level' % ln, 'Sc %d Level' % ln]
184 elif c >= 224: # Application specific commands
44789507
UH
185 if self.dev_type == 8:
186 x = dali_device_type8.get(c, ['Unknown App', 'Unk'])
b26c713b
JS
187 else:
188 x = ['Application Specific Command %d' % c, 'App Cmd %d' % c]
189 else:
44789507 190 x = dali_commands.get(c, ['Unknown', 'Unk'])
b26c713b
JS
191 s = ['Command: %d (%s)' % (c, x[0]), 'Com: %d (%s)' % (c, x[1]),
192 'Com: %d' % c, 'C: %d' % c, 'C']
193 else:
194 s = ['Arc Power Level: %d' % c, 'Level: %d' % c,
195 'Lev: %d' % c, 'L: %d' % c, 'L']
196 self.putb(9, 16, [5, s])
197
198 def reset_decoder_state(self):
199 self.edges, self.bits, self.ss_es_bits = [], [], []
200 self.state = 'IDLE'
b26c713b 201
02760d3b 202 def decode(self):
b26c713b
JS
203 if not self.samplerate:
204 raise SamplerateError('Cannot decode without samplerate.')
37133b0a 205 bit = 0
02760d3b
UH
206 while True:
207 # TODO: Come up with more appropriate self.wait() conditions.
1b9ef18b 208 (dali,) = self.wait()
b26c713b 209 if self.options['polarity'] == 'active-high':
3b44d89e 210 dali ^= 1 # Invert.
b26c713b
JS
211
212 # State machine.
213 if self.state == 'IDLE':
214 # Wait for any edge (rising or falling).
3b44d89e 215 if self.old_dali == dali:
b26c713b
JS
216 continue
217 self.edges.append(self.samplenum)
218 self.state = 'PHASE0'
3b44d89e 219 self.old_dali = dali
b26c713b
JS
220 continue
221
3b44d89e 222 if self.old_dali != dali:
b26c713b 223 self.edges.append(self.samplenum)
3b44d89e 224 elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)):
b26c713b
JS
225 self.edges.append(self.samplenum - int(self.halfbit * 0.5))
226 else:
227 continue
228
a8933728 229 bit = self.old_dali
b26c713b
JS
230 if self.state == 'PHASE0':
231 self.phase0 = bit
232 self.state = 'PHASE1'
233 elif self.state == 'PHASE1':
37133b0a 234 if (bit == 1) and (self.phase0 == 1): # Stop bit.
b26c713b 235 if len(self.bits) == 17 or len(self.bits) == 9:
37133b0a 236 # Forward or Backward.
b26c713b
JS
237 self.handle_bits(len(self.bits))
238 self.reset_decoder_state() # Reset upon errors.
239 continue
240 else:
241 self.bits.append([self.edges[-3], bit])
242 self.state = 'PHASE0'
243
3b44d89e 244 self.old_dali = dali