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 = 'DALI lighting control protocol.'
36 {'id': 'dali', 'name': 'DALI', 'desc': 'DALI data line'},
39 {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
40 'values': ('active-low', 'active-high')},
44 ('startbit', 'Startbit'),
45 ('sbit', 'Select bit'),
46 ('ybit', 'Individual or group'),
47 ('address', 'Address'),
48 ('command', 'Command'),
49 ('reply', 'Reply data'),
53 ('bits', 'Bits', (0,)),
54 ('raw', 'Raw data', (7,)),
55 ('fields', 'Fields', (1, 2, 3, 4, 5, 6)),
59 self.samplerate = None
61 self.edges, self.bits, self.ss_es_bits = [], [], []
66 self.out_ann = self.register(srd.OUTPUT_ANN)
67 self.old_dali = 1 if self.options['polarity'] == 'active-low' else 0
69 def metadata(self, key, value):
70 if key == srd.SRD_CONF_SAMPLERATE:
71 self.samplerate = value
72 # One bit: 833.33us (one half low, one half high).
73 # This is how may samples are in 1TE.
74 self.halfbit = int((self.samplerate * 0.0008333) / 2.0)
76 def putb(self, bit1, bit2, data):
77 ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1]
78 self.put(ss, es, self.out_ann, data)
80 def handle_bits(self, length):
81 a, c, f, g, b = 0, 0, 0, 0, self.bits
82 # Individual raw bits.
83 for i in range(length):
85 ss = max(0, self.bits[0][0])
87 ss = self.ss_es_bits[i - 1][1]
88 es = self.bits[i][0] + (self.halfbit * 2)
89 self.ss_es_bits.append([ss, es])
90 self.putb(i, i, [0, ['%d' % self.bits[i][1]]])
92 s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S']
93 self.putb(0, 0, [1, s])
94 self.putb(0, 0, [7, s])
97 f |= (b[1 + i][1] << (7 - i))
98 if length == 9: # BACKWARD Frame
99 s = ['Reply: %02X' % f, 'Rply: %02X' % f,
100 'Rep: %02X' % f, 'R: %02X' % f, 'R']
101 self.putb(1, 8, [7, s])
102 s = ['Reply: %d' % f, 'Rply: %d' % f,
103 'Rep: %d' % f, 'R: %d' % f, 'R']
104 self.putb(1, 8, [6, s])
108 # Bits[9:16]: Command/data (MSB-first)
110 c |= (b[9 + i][1] << (7 - i))
112 s = ['Raw data: %02X' % f, 'Raw: %02X' % f,
113 'Raw: %02X' % f, 'R: %02X' % f, 'R']
114 self.putb(1, 8, [7, s])
115 s = ['Raw data: %02X' % c, 'Raw: %02X' % c,
116 'Raw: %02X' % c, 'R: %02X' % c, 'R']
117 self.putb(9, 16, [7, s])
119 # Bits[8:8]: Select bit
120 # s = ['Selectbit: %d' % b[8][1], 'SEL: %d' % b[8][1], 'SEL', 'SE', 'S']
122 s = ['Command', 'Comd', 'COM', 'CO', 'C']
124 s = ['Arc Power Level', 'Arc Pwr', 'ARC', 'AC', 'A']
125 self.putb(8, 8, [1, s])
127 # f &= 254 # Clear the select bit.
128 if f >= 254: # BROADCAST
129 s = ['BROADCAST', 'Brdcast', 'BC', 'B', 'B']
130 self.putb(1, 7, [5, s])
131 elif f >= 160: # Extended command 0b10100000
132 if f == 0xC1: # DALI_ENABLE_DEVICE_TYPE_X
134 x = extendedCommands.get(f, ['Unknown', 'Unk'])
135 s = ['Extended Command: %02X (%s)' % (f, x[0]),
136 'XC: %02X (%s)' % (f, x[1]),
137 'XC: %02X' % f, 'X: %02X' % f, 'X']
138 self.putb(1, 8, [5, s])
139 elif f >= 128: # Group
141 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
142 self.putb(1, 1, [3, s])
144 s = ['Group address: %d' % g, 'Group: %d' % g,
145 'GP: %d' % g, 'G: %d' % g, 'G']
146 self.putb(2,7, [4, s])
147 else: # Short address
149 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
150 self.putb(1, 1, [3, s])
152 s = ['Short address: %d' % a, 'Addr: %d' % a,
153 'Addr: %d' % a, 'A: %d' % a, 'A']
154 self.putb(2, 7, [4, s])
156 # Bits[9:16]: Command/data (MSB-first)
157 if f >= 160 and f < 254:
158 if self.devType == -1:
160 s = ['Type: %d' % c, 'Typ: %d' % c,
161 'Typ: %d' % c, 'T: %d' % c, 'D']
164 s = ['Data: %d' % c, 'Dat: %d' % c,
165 'Dat: %d' % c, 'D: %d' % c, 'D']
169 if un == 0x10: # Set scene command
170 x = ['Recall Scene %d' % ln, 'SC %d' % ln]
172 x = ['Store DTR as Scene %d' % ln, 'SC %d = DTR' % ln]
174 x = ['Delete Scene %d' % ln, 'DEL SC %d' % ln]
176 x = ['Add to Group %d' % ln, 'Grp %d Add' % ln]
178 x = ['Remove from Group %d' % ln, 'Grp %d Del' % ln]
180 x = ['Query Scene %d Level' % ln, 'Sc %d Level' % ln]
181 elif c >= 224: # Application specific commands
182 if self.devType == 8:
183 x = DALIDeviceType8.get(c, ['Unknown App', 'Unk'])
185 x = ['Application Specific Command %d' % c, 'App Cmd %d' % c]
187 x = DALICommands.get(c, ['Unknown', 'Unk'])
188 s = ['Command: %d (%s)' % (c, x[0]), 'Com: %d (%s)' % (c, x[1]),
189 'Com: %d' % c, 'C: %d' % c, 'C']
191 s = ['Arc Power Level: %d' % c, 'Level: %d' % c,
192 'Lev: %d' % c, 'L: %d' % c, 'L']
193 self.putb(9, 16, [5, s])
195 def reset_decoder_state(self):
196 self.edges, self.bits, self.ss_es_bits = [], [], []
200 if not self.samplerate:
201 raise SamplerateError('Cannot decode without samplerate.')
204 # TODO: Come up with more appropriate self.wait() conditions.
205 (dali,) = self.wait()
206 if self.options['polarity'] == 'active-high':
210 if self.state == 'IDLE':
211 # Wait for any edge (rising or falling).
212 if self.old_dali == dali:
214 self.edges.append(self.samplenum)
215 self.state = 'PHASE0'
219 if self.old_dali != dali:
220 self.edges.append(self.samplenum)
221 elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)):
222 self.edges.append(self.samplenum - int(self.halfbit * 0.5))
227 if self.state == 'PHASE0':
229 self.state = 'PHASE1'
230 elif self.state == 'PHASE1':
231 if (bit == 1) and (self.phase0 == 1): # Stop bit.
232 if len(self.bits) == 17 or len(self.bits) == 9:
233 # Forward or Backward.
234 self.handle_bits(len(self.bits))
235 self.reset_decoder_state() # Reset upon errors.
238 self.bits.append([self.edges[-3], bit])
239 self.state = 'PHASE0'