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 = [], [], []
63 self.nextSamplePoint = None
64 self.nextSample = None
68 self.out_ann = self.register(srd.OUTPUT_ANN)
69 self.old_dali = 1 if self.options['polarity'] == 'active-low' else 0
71 def metadata(self, key, value):
72 if key == srd.SRD_CONF_SAMPLERATE:
73 self.samplerate = value
74 # One bit: 833.33us (one half low, one half high).
75 # This is how may samples are in 1TE.
76 self.halfbit = int((self.samplerate * 0.0008333) / 2.0)
78 def putb(self, bit1, bit2, data):
79 ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1]
80 self.put(ss, es, self.out_ann, data)
82 def handle_bits(self, length):
83 a, c, f, g, b = 0, 0, 0, 0, self.bits
84 # Individual raw bits.
85 for i in range(length):
87 ss = max(0, self.bits[0][0])
89 ss = self.ss_es_bits[i - 1][1]
90 es = self.bits[i][0] + (self.halfbit * 2)
91 self.ss_es_bits.append([ss, es])
92 self.putb(i, i, [0, ['%d' % self.bits[i][1]]])
94 s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S']
95 self.putb(0, 0, [1, s])
96 self.putb(0, 0, [7, s])
99 f |= (b[1 + i][1] << (7 - i))
100 if length == 9: # BACKWARD Frame
101 s = ['Reply: %02X' % f, 'Rply: %02X' % f,
102 'Rep: %02X' % f, 'R: %02X' % f, 'R']
103 self.putb(1, 8, [7, s])
104 s = ['Reply: %d' % f, 'Rply: %d' % f,
105 'Rep: %d' % f, 'R: %d' % f, 'R']
106 self.putb(1, 8, [6, s])
110 # Bits[9:16]: Command/data (MSB-first)
112 c |= (b[9 + i][1] << (7 - i))
114 s = ['Raw data: %02X' % f, 'Raw: %02X' % f,
115 'Raw: %02X' % f, 'R: %02X' % f, 'R']
116 self.putb(1, 8, [7, s])
117 s = ['Raw data: %02X' % c, 'Raw: %02X' % c,
118 'Raw: %02X' % c, 'R: %02X' % c, 'R']
119 self.putb(9, 16, [7, s])
121 # Bits[8:8]: Select bit
122 # s = ['Selectbit: %d' % b[8][1], 'SEL: %d' % b[8][1], 'SEL', 'SE', 'S']
124 s = ['Command', 'Comd', 'COM', 'CO', 'C']
126 s = ['Arc Power Level', 'Arc Pwr', 'ARC', 'AC', 'A']
127 self.putb(8, 8, [1, s])
129 # f &= 254 # Clear the select bit.
130 if f >= 254: # BROADCAST
131 s = ['BROADCAST', 'Brdcast', 'BC', 'B', 'B']
132 self.putb(1, 7, [5, s])
133 elif f >= 160: # Extended command 0b10100000
134 if f == 0xC1: # DALI_ENABLE_DEVICE_TYPE_X
136 x = extendedCommands.get(f, ['Unknown', 'Unk'])
137 s = ['Extended Command: %02X (%s)' % (f, x[0]),
138 'XC: %02X (%s)' % (f, x[1]),
139 'XC: %02X' % f, 'X: %02X' % f, 'X']
140 self.putb(1, 8, [5, s])
141 elif f >= 128: # Group
143 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
144 self.putb(1, 1, [3, s])
146 s = ['Group address: %d' % g, 'Group: %d' % g,
147 'GP: %d' % g, 'G: %d' % g, 'G']
148 self.putb(2,7, [4, s])
149 else: # Short address
151 s = ['YBit: %d' % b[1][1], 'YB: %d' % b[1][1], 'YB', 'Y', 'Y']
152 self.putb(1, 1, [3, s])
154 # x = system.get(a, ['Unknown', 'Unk'])
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.devType == -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.devType == 8:
186 x = DALIDeviceType8.get(c, ['Unknown App', 'Unk'])
188 x = ['Application Specific Command %d' % c, 'App Cmd %d' % c]
190 x = DALICommands.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 = [], [], []
201 # self.devType = None
203 def decode(self, ss, es, data):
204 if not self.samplerate:
205 raise SamplerateError('Cannot decode without samplerate.')
207 for (self.samplenum, pins) in data:
210 # data.logic_mask = 1
211 # data.cur_pos = self.samplenum
212 # data.edge_index = -1
213 if self.options['polarity'] == 'active-high':
214 self.dali ^= 1 # Invert.
217 if self.state == 'IDLE':
218 # Wait for any edge (rising or falling).
219 if self.old_dali == self.dali:
220 # data.exp_logic = self.exp_logic
221 # data.logic_mask = 1
222 # logic.cur_pos = self.samplenum
224 self.edges.append(self.samplenum)
225 self.state = 'PHASE0'
226 self.old_dali = self.dali
227 # Get the next sample point.
228 # self.nextSamplePoint = self.samplenum + int(self.halfbit / 2)
229 self.old_dali = self.dali
231 # data.itercnt += int((self.halfbit - 1) * 0.5)
234 # if(self.samplenum == self.nextSamplePoint):
238 if (self.old_dali != self.dali):
239 self.edges.append(self.samplenum)
240 elif (self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5))):
241 self.edges.append(self.samplenum - int(self.halfbit * 0.5))
246 if self.state == 'PHASE0':
248 self.state = 'PHASE1'
249 elif self.state == 'PHASE1':
250 if (bit == 1) and (self.phase0 == 1): # Stop bit
251 if len(self.bits) == 17 or len(self.bits) == 9:
252 # Forward or Backward
253 self.handle_bits(len(self.bits))
254 self.reset_decoder_state() # Reset upon errors.
257 self.bits.append([self.edges[-3], bit])
258 self.state = 'PHASE0'
260 # self.nextSamplePoint = self.edges[-1] + int(self.halfbit / 2)
262 self.old_dali = self.dali