2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2015 Jeremy Swanson <jeremy@rakocontrols.com>
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.
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.
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/>.
20 import sigrokdecode as srd
23 class SamplerateError(Exception):
26 class Decoder(srd.Decoder):
30 longname = 'Digital Addressable Lighting Interface'
31 desc = 'Digital Addressable Lighting Interface (DALI) protocol.'
35 tags = ['Embedded/industrial', 'Lighting']
37 {'id': 'dali', 'name': 'DALI', 'desc': 'DALI data line'},
40 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
41 'values': ('active-low', 'active-high')},
45 ('startbit', 'Startbit'),
46 ('sbit', 'Select bit'),
47 ('ybit', 'Individual or group'),
48 ('address', 'Address'),
49 ('command', 'Command'),
50 ('reply', 'Reply data'),
54 ('bits', 'Bits', (0,)),
55 ('raw', 'Raw data', (7,)),
56 ('fields', 'Fields', (1, 2, 3, 4, 5, 6)),
63 self.samplerate = None
65 self.edges, self.bits, self.ss_es_bits = [], [], []
70 self.out_ann = self.register(srd.OUTPUT_ANN)
71 self.old_dali = 1 if self.options['polarity'] == 'active-low' else 0
73 def metadata(self, key, value):
74 if key == srd.SRD_CONF_SAMPLERATE:
75 self.samplerate = value
76 # One bit: 833.33us (one half low, one half high).
77 # This is how may samples are in 1TE.
78 self.halfbit = int((self.samplerate * 0.0008333) / 2.0)
80 def putb(self, bit1, bit2, data):
81 ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1]
82 self.put(ss, es, self.out_ann, data)
84 def handle_bits(self, length):
85 a, c, f, g, b = 0, 0, 0, 0, self.bits
86 # Individual raw bits.
87 for i in range(length):
89 ss = max(0, self.bits[0][0])
91 ss = self.ss_es_bits[i - 1][1]
92 es = self.bits[i][0] + (self.halfbit * 2)
93 self.ss_es_bits.append([ss, es])
94 self.putb(i, i, [0, ['%d' % self.bits[i][1]]])
96 s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S']
97 self.putb(0, 0, [1, s])
98 self.putb(0, 0, [7, s])
101 f |= (b[1 + i][1] << (7 - i))
102 if length == 9: # BACKWARD Frame
103 s = ['Reply: %02X' % f, 'Rply: %02X' % f,
104 'Rep: %02X' % f, 'R: %02X' % f, 'R']
105 self.putb(1, 8, [7, s])
106 s = ['Reply: %d' % f, 'Rply: %d' % f,
107 'Rep: %d' % f, 'R: %d' % f, 'R']
108 self.putb(1, 8, [6, s])
112 # Bits[9:16]: Command/data (MSB-first)
114 c |= (b[9 + i][1] << (7 - i))
116 s = ['Raw data: %02X' % f, 'Raw: %02X' % f,
117 'Raw: %02X' % f, 'R: %02X' % f, 'R']
118 self.putb(1, 8, [7, s])
119 s = ['Raw data: %02X' % c, 'Raw: %02X' % c,
120 'Raw: %02X' % c, 'R: %02X' % c, 'R']
121 self.putb(9, 16, [7, s])
123 # Bits[8:8]: Select bit
124 # s = ['Selectbit: %d' % b[8][1], 'SEL: %d' % b[8][1], 'SEL', 'SE', 'S']
126 s = ['Command', 'Comd', 'COM', 'CO', 'C']
128 s = ['Arc Power Level', 'Arc Pwr', 'ARC', 'AC', 'A']
129 self.putb(8, 8, [1, s])
131 # f &= 254 # Clear the select bit.
132 if f >= 254: # BROADCAST
133 s = ['BROADCAST', 'Brdcast', 'BC', 'B', 'B']
134 self.putb(1, 7, [5, s])
135 elif f >= 160: # Extended command 0b10100000
136 if f == 0xC1: # DALI_ENABLE_DEVICE_TYPE_X
138 x = extended_commands.get(f, ['Unknown', 'Unk'])
139 s = ['Extended Command: %02X (%s)' % (f, x[0]),
140 'XC: %02X (%s)' % (f, x[1]),
141 'XC: %02X' % f, 'X: %02X' % f, 'X']
142 self.putb(1, 8, [5, s])
143 elif f >= 128: # Group
145 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
146 self.putb(1, 1, [3, s])
148 s = ['Group address: %d' % g, 'Group: %d' % g,
149 'GP: %d' % g, 'G: %d' % g, 'G']
150 self.putb(2,7, [4, s])
151 else: # Short address
153 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
154 self.putb(1, 1, [3, s])
156 s = ['Short address: %d' % a, 'Addr: %d' % a,
157 'Addr: %d' % a, 'A: %d' % a, 'A']
158 self.putb(2, 7, [4, s])
160 # Bits[9:16]: Command/data (MSB-first)
161 if f >= 160 and f < 254:
162 if self.dev_type == -1:
164 s = ['Type: %d' % c, 'Typ: %d' % c,
165 'Typ: %d' % c, 'T: %d' % c, 'D']
168 s = ['Data: %d' % c, 'Dat: %d' % c,
169 'Dat: %d' % c, 'D: %d' % c, 'D']
173 if un == 0x10: # Set scene command
174 x = ['Recall Scene %d' % ln, 'SC %d' % ln]
176 x = ['Store DTR as Scene %d' % ln, 'SC %d = DTR' % ln]
178 x = ['Delete Scene %d' % ln, 'DEL SC %d' % ln]
180 x = ['Add to Group %d' % ln, 'Grp %d Add' % ln]
182 x = ['Remove from Group %d' % ln, 'Grp %d Del' % ln]
184 x = ['Query Scene %d Level' % ln, 'Sc %d Level' % ln]
185 elif c >= 224: # Application specific commands
186 if self.dev_type == 8:
187 x = dali_device_type8.get(c, ['Unknown App', 'Unk'])
189 x = ['Application Specific Command %d' % c, 'App Cmd %d' % c]
191 x = dali_commands.get(c, ['Unknown', 'Unk'])
192 s = ['Command: %d (%s)' % (c, x[0]), 'Com: %d (%s)' % (c, x[1]),
193 'Com: %d' % c, 'C: %d' % c, 'C']
195 s = ['Arc Power Level: %d' % c, 'Level: %d' % c,
196 'Lev: %d' % c, 'L: %d' % c, 'L']
197 self.putb(9, 16, [5, s])
199 def reset_decoder_state(self):
200 self.edges, self.bits, self.ss_es_bits = [], [], []
204 if not self.samplerate:
205 raise SamplerateError('Cannot decode without samplerate.')
208 # TODO: Come up with more appropriate self.wait() conditions.
209 (dali,) = self.wait()
210 if self.options['polarity'] == 'active-high':
214 if self.state == 'IDLE':
215 # Wait for any edge (rising or falling).
216 if self.old_dali == dali:
218 self.edges.append(self.samplenum)
219 self.state = 'PHASE0'
223 if self.old_dali != dali:
224 self.edges.append(self.samplenum)
225 elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)):
226 self.edges.append(self.samplenum - int(self.halfbit * 0.5))
231 if self.state == 'PHASE0':
233 self.state = 'PHASE1'
234 elif self.state == 'PHASE1':
235 if (bit == 1) and (self.phase0 == 1): # Stop bit.
236 if len(self.bits) == 17 or len(self.bits) == 9:
237 # Forward or Backward.
238 self.handle_bits(len(self.bits))
239 self.reset_decoder_state() # Reset upon errors.
242 self.bits.append([self.edges[-3], bit])
243 self.state = 'PHASE0'