]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spdif/pd.py
avr_isp: Add more parts
[libsigrokdecode.git] / decoders / spdif / pd.py
CommitLineData
cb6d4c6d
GW
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2014 Guenther Wenninger <robin@bitschubbser.org>
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
4539e9ca 17## along with this program; if not, see <http://www.gnu.org/licenses/>.
cb6d4c6d
GW
18##
19
20import sigrokdecode as srd
21
22class SamplerateError(Exception):
23 pass
24
25class Decoder(srd.Decoder):
5e39fa54 26 api_version = 3
cb6d4c6d
GW
27 id = 'spdif'
28 name = 'S/PDIF'
29 longname = 'Sony/Philips Digital Interface Format'
30 desc = 'Serial bus for connecting digital audio devices.'
31 license = 'gplv2+'
32 inputs = ['logic']
6cbba91f 33 outputs = []
d6d8a8a4 34 tags = ['Audio', 'PC']
cb6d4c6d
GW
35 channels = (
36 {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
37 )
38 annotations = (
39 ('bitrate', 'Bitrate / baudrate'),
40 ('preamble', 'Preamble'),
e144452b
UH
41 ('bit', 'Bit'),
42 ('aux', 'Auxillary-audio-databit'),
43 ('sample', 'Audio Sample'),
cb6d4c6d
GW
44 ('validity', 'Data Valid'),
45 ('subcode', 'Subcode data'),
46 ('chan_stat', 'Channnel Status'),
47 ('parity', 'Parity Bit'),
48 )
49 annotation_rows = (
cb6d4c6d 50 ('bits', 'Bits', (2,)),
9d09d6ed 51 ('info', 'Info', (0, 1, 3, 5, 6, 7, 8)),
cb6d4c6d
GW
52 ('samples', 'Samples', (4,)),
53 )
54
55 def putx(self, ss, es, data):
56 self.put(ss, es, self.out_ann, data)
57
cc16130e
UH
58 def puty(self, data):
59 self.put(self.ss_edge, self.samplenum, self.out_ann, data)
60
92b7b49f 61 def __init__(self):
10aeb8ea
GS
62 self.reset()
63
64 def reset(self):
5302d1e9 65 self.state = 'GET FIRST PULSE WIDTH'
cb6d4c6d
GW
66 self.ss_edge = None
67 self.first_edge = True
5e39fa54 68 self.samplenum_prev_edge = 0
cb6d4c6d
GW
69 self.pulse_width = 0
70
71 self.clocks = []
72 self.range1 = 0
73 self.range2 = 0
74
75 self.preamble_state = 0
76 self.preamble = []
77 self.seen_preamble = False
78 self.last_preamble = 0
79
028589e6
AM
80 self.bitrate_message_start = 0
81 self.bitrate_message_end = 0
82 self.frame_counter = 0
83 self.frame_start = 0
84 self.frame_length = 0
85
86 self.sampleratetmp = 1
87
cb6d4c6d
GW
88 self.first_one = True
89 self.subframe = []
90
91 def start(self):
92 self.out_ann = self.register(srd.OUTPUT_ANN)
93
94 def metadata(self, key, value):
95 if key == srd.SRD_CONF_SAMPLERATE:
96 self.samplerate = value
97
58636105 98 def get_pulse_type(self):
58636105 99 if self.pulse_width >= self.range2:
cb6d4c6d 100 return 2
58636105 101 elif self.pulse_width >= self.range1:
cb6d4c6d
GW
102 return 0
103 else:
104 return 1
105
eb148e7a
UH
106 def find_first_pulse_width(self):
107 if self.pulse_width != 0:
108 self.clocks.append(self.pulse_width)
5302d1e9 109 self.state = 'GET SECOND PULSE WIDTH'
51194ffc 110 self.puty([2, ['Found width 1: %d' % self.pulse_width, 'W1: %d' % self.pulse_width]])
028589e6 111 self.ss_edge = self.samplenum
eb148e7a
UH
112
113 def find_second_pulse_width(self):
114 if self.pulse_width > (self.clocks[0] * 1.3) or \
028589e6 115 self.pulse_width <= (self.clocks[0] * 0.75):
51194ffc 116 self.puty([2, ['Found width 2: %d' % self.pulse_width, 'W2: %d' % self.pulse_width]])
eb148e7a 117 self.clocks.append(self.pulse_width)
5302d1e9 118 self.state = 'GET THIRD PULSE WIDTH'
028589e6 119 else:
51194ffc 120 self.puty([2, ['Search width 2: %d' % self.pulse_width, 'SW2: %d' % self.pulse_width]])
028589e6 121 self.ss_edge = self.samplenum
eb148e7a
UH
122
123 def find_third_pulse_width(self):
124 if not ((self.pulse_width > (self.clocks[0] * 1.3) or \
028589e6 125 self.pulse_width <= (self.clocks[0] * 0.75)) \
eb148e7a 126 and (self.pulse_width > (self.clocks[1] * 1.3) or \
028589e6 127 self.pulse_width <= (self.clocks[1] * 0.75))):
51194ffc 128 self.puty([2, ['Search width 3: %d' % self.pulse_width, 'SW3: %d' % self.pulse_width]])
028589e6 129 self.ss_edge = self.samplenum
eb148e7a 130 return
028589e6 131 else:
51194ffc 132 self.puty([2, ['Found width 3: %d' % self.pulse_width, 'W3: %d' % self.pulse_width]])
028589e6
AM
133 self.ss_edge = self.samplenum
134 # The message of the calculated bitrate should start at this sample
135 # (right after the synchronisation).
136 self.bitrate_message_start = self.samplenum
eb148e7a
UH
137
138 self.clocks.append(self.pulse_width)
139 self.clocks.sort()
140 self.range1 = (self.clocks[0] + self.clocks[1]) / 2
141 self.range2 = (self.clocks[1] + self.clocks[2]) / 2
028589e6
AM
142 # Give some feedback during synchronisation and inform if sample rate
143 # is too low.
144 if self.clocks[0] <= 3:
145 self.putx(0, self.samplenum, [0, ['Short pulses detected. Increase sample rate!']])
146 raise SamplerateError('Short pulses detected')
147 else:
148 self.putx(0, self.samplenum, [0, ['Synchronisation']])
eb148e7a
UH
149 self.ss_edge = 0
150
028589e6
AM
151 # Mostly, the synchronisation ends with a long pulse because they
152 # appear rarely. A skip of the next pulse will then prevent a 'M'
153 # frame to be labeled an unknown preamble for the first decoded frame.
154 (data,) = self.wait({0: 'e'})
eb148e7a 155
028589e6
AM
156 self.pulse_width = self.samplenum - self.samplenum_prev_edge
157 self.samplenum_prev_edge = self.samplenum
eb148e7a
UH
158 self.last_preamble = self.samplenum
159
160 # We are done recovering the clock, now let's decode the data stream.
5302d1e9 161 self.state = 'DECODE STREAM'
eb148e7a
UH
162
163 def decode_stream(self):
58636105 164 pulse = self.get_pulse_type()
eb148e7a
UH
165
166 if not self.seen_preamble:
167 # This is probably the start of a preamble, decode it.
168 if pulse == 2:
58636105 169 self.preamble.append(self.get_pulse_type())
5302d1e9 170 self.state = 'DECODE PREAMBLE'
028589e6
AM
171 self.ss_edge = self.samplenum - self.pulse_width
172 # Use the first ten frames to calculate bit rates
173 if self.frame_counter == 0:
174 # This is the first preamble to be decoded. Measurement of
175 # bit rates starts here.
176 self.frame_start = self.samplenum
177 # The bit rate message should end here.
178 self.bitrate_message_end = self.ss_edge
179 elif self.frame_counter == 10:
180 self.frame_length = self.samplenum - self.frame_start
181 # Use section between end of synchronisation and start of
182 # first preamble to show measured bit rates.
183 if self.samplerate:
184 self.putx(self.bitrate_message_start, self.bitrate_message_end,\
185 [0, ['Audio samplingrate: %6.2f kHz; Bit rate: %6.3f MBit/s' %\
186 ((self.samplerate / 200 / self.frame_length), (self.samplerate / 200 * 64 / 1000 / self.frame_length))]])
187 else:
188 self.putx(self.bitrate_message_start, self.bitrate_message_end, [0, ['No sample rate given']])
189 self.frame_counter += 1
eb148e7a
UH
190 return
191
192 # We've seen a preamble.
193 if pulse == 1 and self.first_one:
194 self.first_one = False
028589e6 195 self.subframe.append([pulse, self.samplenum - self.pulse_width, self.samplenum])
eb148e7a
UH
196 elif pulse == 1 and not self.first_one:
197 self.subframe[-1][2] = self.samplenum
198 self.putx(self.subframe[-1][1], self.samplenum, [2, ['1']])
199 self.bitcount += 1
200 self.first_one = True
201 else:
028589e6
AM
202 self.subframe.append([pulse, self.samplenum - self.pulse_width, self.samplenum])
203 self.putx(self.samplenum - self.pulse_width, self.samplenum, [2, ['0']])
eb148e7a
UH
204 self.bitcount += 1
205
206 if self.bitcount == 28:
207 aux_audio_data = self.subframe[0:4]
208 sam, sam_rot = '', ''
209 for a in aux_audio_data:
210 sam = sam + str(a[0])
211 sam_rot = str(a[0]) + sam_rot
212 sample = self.subframe[4:24]
213 for s in sample:
214 sam = sam + str(s[0])
215 sam_rot = str(s[0]) + sam_rot
216 validity = self.subframe[24:25]
217 subcode_data = self.subframe[25:26]
218 channel_status = self.subframe[26:27]
219 parity = self.subframe[27:28]
220
221 self.putx(aux_audio_data[0][1], aux_audio_data[3][2], \
222 [3, ['Aux 0x%x' % int(sam, 2), '0x%x' % int(sam, 2)]])
223 self.putx(sample[0][1], sample[19][2], \
224 [3, ['Sample 0x%x' % int(sam, 2), '0x%x' % int(sam, 2)]])
225 self.putx(aux_audio_data[0][1], sample[19][2], \
226 [4, ['Audio 0x%x' % int(sam_rot, 2), '0x%x' % int(sam_rot, 2)]])
227 if validity[0][0] == 0:
228 self.putx(validity[0][1], validity[0][2], [5, ['V']])
229 else:
230 self.putx(validity[0][1], validity[0][2], [5, ['E']])
231 self.putx(subcode_data[0][1], subcode_data[0][2],
232 [6, ['S: %d' % subcode_data[0][0]]])
233 self.putx(channel_status[0][1], channel_status[0][2],
234 [7, ['C: %d' % channel_status[0][0]]])
235 self.putx(parity[0][1], parity[0][2], [8, ['P: %d' % parity[0][0]]])
236
237 self.subframe = []
238 self.seen_preamble = False
239 self.bitcount = 0
240
5302d1e9 241 def decode_preamble(self):
eb148e7a 242 if self.preamble_state == 0:
58636105 243 self.preamble.append(self.get_pulse_type())
eb148e7a
UH
244 self.preamble_state = 1
245 elif self.preamble_state == 1:
58636105 246 self.preamble.append(self.get_pulse_type())
eb148e7a
UH
247 self.preamble_state = 2
248 elif self.preamble_state == 2:
58636105 249 self.preamble.append(self.get_pulse_type())
eb148e7a 250 self.preamble_state = 0
5302d1e9 251 self.state = 'DECODE STREAM'
eb148e7a 252 if self.preamble == [2, 0, 1, 0]:
cc16130e 253 self.puty([1, ['Preamble W', 'W']])
eb148e7a 254 elif self.preamble == [2, 2, 1, 1]:
cc16130e 255 self.puty([1, ['Preamble M', 'M']])
eb148e7a 256 elif self.preamble == [2, 1, 1, 2]:
cc16130e 257 self.puty([1, ['Preamble B', 'B']])
eb148e7a 258 else:
868fd207 259 self.puty([1, ['Unknown Preamble', 'Unknown Prea.', 'U']])
eb148e7a
UH
260 self.preamble = []
261 self.seen_preamble = True
262 self.bitcount = 0
263 self.first_one = True
264
265 self.last_preamble = self.samplenum
266
5e39fa54 267 def decode(self):
028589e6 268 # Set samplerate to 0 if it is not given. Decoding is still possible.
cc75bd23 269 if not self.samplerate:
028589e6
AM
270 self.samplerate = 0
271
272 # Throw away first two edges as it might be mangled data.
5e39fa54 273 self.wait({0: 'e'})
028589e6
AM
274 self.wait({0: 'e'})
275 self.ss_edge = 0
276 self.puty([2, ['Skip']])
277 self.ss_edge = self.samplenum
278 self.samplenum_prev_edge = self.samplenum
5e39fa54
UH
279
280 while True:
281 # Wait for any edge (rising or falling).
282 (data,) = self.wait({0: 'e'})
028589e6 283 self.pulse_width = self.samplenum - self.samplenum_prev_edge
5e39fa54
UH
284 self.samplenum_prev_edge = self.samplenum
285
286 if self.state == 'GET FIRST PULSE WIDTH':
287 self.find_first_pulse_width()
288 elif self.state == 'GET SECOND PULSE WIDTH':
289 self.find_second_pulse_width()
290 elif self.state == 'GET THIRD PULSE WIDTH':
291 self.find_third_pulse_width()
292 elif self.state == 'DECODE STREAM':
293 self.decode_stream()
294 elif self.state == 'DECODE PREAMBLE':
295 self.decode_preamble()