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)),
62 self.samplerate = None
64 self.edges, self.bits, self.ss_es_bits = [], [], []
69 self.out_ann = self.register(srd.OUTPUT_ANN)
70 self.old_dali = 1 if self.options['polarity'] == 'active-low' else 0
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)
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)
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):
88 ss = max(0, self.bits[0][0])
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]]])
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])
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])
111 # Bits[9:16]: Command/data (MSB-first)
113 c |= (b[9 + i][1] << (7 - i))
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])
122 # Bits[8:8]: Select bit
123 # s = ['Selectbit: %d' % b[8][1], 'SEL: %d' % b[8][1], 'SEL', 'SE', 'S']
125 s = ['Command', 'Comd', 'COM', 'CO', 'C']
127 s = ['Arc Power Level', 'Arc Pwr', 'ARC', 'AC', 'A']
128 self.putb(8, 8, [1, s])
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
137 x = extended_commands.get(f, ['Unknown', 'Unk'])
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
144 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
145 self.putb(1, 1, [3, s])
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
152 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
153 self.putb(1, 1, [3, s])
155 s = ['Short address: %d' % a, 'Addr: %d' % a,
156 'Addr: %d' % a, 'A: %d' % a, 'A']
157 self.putb(2, 7, [4, s])
159 # Bits[9:16]: Command/data (MSB-first)
160 if f >= 160 and f < 254:
161 if self.dev_type == -1:
163 s = ['Type: %d' % c, 'Typ: %d' % c,
164 'Typ: %d' % c, 'T: %d' % c, 'D']
167 s = ['Data: %d' % c, 'Dat: %d' % c,
168 'Dat: %d' % c, 'D: %d' % c, 'D']
172 if un == 0x10: # Set scene command
173 x = ['Recall Scene %d' % ln, 'SC %d' % ln]
175 x = ['Store DTR as Scene %d' % ln, 'SC %d = DTR' % ln]
177 x = ['Delete Scene %d' % ln, 'DEL SC %d' % ln]
179 x = ['Add to Group %d' % ln, 'Grp %d Add' % ln]
181 x = ['Remove from Group %d' % ln, 'Grp %d Del' % ln]
183 x = ['Query Scene %d Level' % ln, 'Sc %d Level' % ln]
184 elif c >= 224: # Application specific commands
185 if self.dev_type == 8:
186 x = dali_device_type8.get(c, ['Unknown App', 'Unk'])
188 x = ['Application Specific Command %d' % c, 'App Cmd %d' % c]
190 x = dali_commands.get(c, ['Unknown', 'Unk'])
191 s = ['Command: %d (%s)' % (c, x[0]), 'Com: %d (%s)' % (c, x[1]),
192 'Com: %d' % c, 'C: %d' % c, 'C']
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])
198 def reset_decoder_state(self):
199 self.edges, self.bits, self.ss_es_bits = [], [], []
203 if not self.samplerate:
204 raise SamplerateError('Cannot decode without samplerate.')
207 # TODO: Come up with more appropriate self.wait() conditions.
208 (dali,) = self.wait()
209 if self.options['polarity'] == 'active-high':
213 if self.state == 'IDLE':
214 # Wait for any edge (rising or falling).
215 if self.old_dali == dali:
217 self.edges.append(self.samplenum)
218 self.state = 'PHASE0'
222 if self.old_dali != dali:
223 self.edges.append(self.samplenum)
224 elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)):
225 self.edges.append(self.samplenum - int(self.halfbit * 0.5))
230 if self.state == 'PHASE0':
232 self.state = 'PHASE1'
233 elif self.state == 'PHASE1':
234 if (bit == 1) and (self.phase0 == 1): # Stop bit.
235 if len(self.bits) == 17 or len(self.bits) == 9:
236 # Forward or Backward.
237 self.handle_bits(len(self.bits))
238 self.reset_decoder_state() # Reset upon errors.
241 self.bits.append([self.edges[-3], bit])
242 self.state = 'PHASE0'