]> sigrok.org Git - libsigrokdecode.git/blob - decoders/spdif/pd.py
avr_isp: Add more parts
[libsigrokdecode.git] / decoders / spdif / pd.py
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
17 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
18 ##
19
20 import sigrokdecode as srd
21
22 class SamplerateError(Exception):
23     pass
24
25 class Decoder(srd.Decoder):
26     api_version = 3
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']
33     outputs = []
34     tags = ['Audio', 'PC']
35     channels = (
36         {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
37     )
38     annotations = (
39         ('bitrate', 'Bitrate / baudrate'),
40         ('preamble', 'Preamble'),
41         ('bit', 'Bit'),
42         ('aux', 'Auxillary-audio-databit'),
43         ('sample', 'Audio Sample'),
44         ('validity', 'Data Valid'),
45         ('subcode', 'Subcode data'),
46         ('chan_stat', 'Channnel Status'),
47         ('parity', 'Parity Bit'),
48     )
49     annotation_rows = (
50         ('bits', 'Bits', (2,)),
51         ('info', 'Info', (0, 1, 3, 5, 6, 7, 8)),
52         ('samples', 'Samples', (4,)),
53     )
54
55     def putx(self, ss, es, data):
56         self.put(ss, es, self.out_ann, data)
57
58     def puty(self, data):
59         self.put(self.ss_edge, self.samplenum, self.out_ann, data)
60
61     def __init__(self):
62         self.reset()
63
64     def reset(self):
65         self.state = 'GET FIRST PULSE WIDTH'
66         self.ss_edge = None
67         self.first_edge = True
68         self.samplenum_prev_edge = 0
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
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
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
98     def get_pulse_type(self):
99         if self.pulse_width >= self.range2:
100             return 2
101         elif self.pulse_width >= self.range1:
102             return 0
103         else:
104             return 1
105
106     def find_first_pulse_width(self):
107         if self.pulse_width != 0:
108             self.clocks.append(self.pulse_width)
109             self.state = 'GET SECOND PULSE WIDTH'
110             self.puty([2, ['Found width 1: %d' % self.pulse_width, 'W1: %d' % self.pulse_width]])
111             self.ss_edge = self.samplenum
112
113     def find_second_pulse_width(self):
114         if self.pulse_width > (self.clocks[0] * 1.3) or \
115                 self.pulse_width <= (self.clocks[0] * 0.75):
116             self.puty([2, ['Found width 2: %d' % self.pulse_width, 'W2: %d' % self.pulse_width]])
117             self.clocks.append(self.pulse_width)
118             self.state = 'GET THIRD PULSE WIDTH'
119         else:
120             self.puty([2, ['Search width 2: %d' % self.pulse_width, 'SW2: %d' % self.pulse_width]])
121         self.ss_edge = self.samplenum
122
123     def find_third_pulse_width(self):
124         if not ((self.pulse_width > (self.clocks[0] * 1.3) or \
125                 self.pulse_width <= (self.clocks[0] * 0.75)) \
126                 and (self.pulse_width > (self.clocks[1] * 1.3) or \
127                 self.pulse_width <= (self.clocks[1] * 0.75))):
128             self.puty([2, ['Search width 3: %d' % self.pulse_width, 'SW3: %d' % self.pulse_width]])
129             self.ss_edge = self.samplenum
130             return
131         else:
132             self.puty([2, ['Found width 3: %d' % self.pulse_width, 'W3: %d' % self.pulse_width]])
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
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
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']])
149         self.ss_edge = 0
150
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'})
155
156         self.pulse_width = self.samplenum - self.samplenum_prev_edge
157         self.samplenum_prev_edge = self.samplenum
158         self.last_preamble = self.samplenum
159
160         # We are done recovering the clock, now let's decode the data stream.
161         self.state = 'DECODE STREAM'
162
163     def decode_stream(self):
164         pulse = self.get_pulse_type()
165
166         if not self.seen_preamble:
167             # This is probably the start of a preamble, decode it.
168             if pulse == 2:
169                 self.preamble.append(self.get_pulse_type())
170                 self.state = 'DECODE PREAMBLE'
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
190             return
191
192         # We've seen a preamble.
193         if pulse == 1 and self.first_one:
194             self.first_one = False
195             self.subframe.append([pulse, self.samplenum - self.pulse_width, self.samplenum])
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:
202             self.subframe.append([pulse, self.samplenum - self.pulse_width, self.samplenum])
203             self.putx(self.samplenum - self.pulse_width, self.samplenum, [2, ['0']])
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
241     def decode_preamble(self):
242         if self.preamble_state == 0:
243             self.preamble.append(self.get_pulse_type())
244             self.preamble_state = 1
245         elif self.preamble_state == 1:
246             self.preamble.append(self.get_pulse_type())
247             self.preamble_state = 2
248         elif self.preamble_state == 2:
249             self.preamble.append(self.get_pulse_type())
250             self.preamble_state = 0
251             self.state = 'DECODE STREAM'
252             if self.preamble == [2, 0, 1, 0]:
253                 self.puty([1, ['Preamble W', 'W']])
254             elif self.preamble == [2, 2, 1, 1]:
255                 self.puty([1, ['Preamble M', 'M']])
256             elif self.preamble == [2, 1, 1, 2]:
257                 self.puty([1, ['Preamble B', 'B']])
258             else:
259                 self.puty([1, ['Unknown Preamble', 'Unknown Prea.', 'U']])
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
267     def decode(self):
268         # Set samplerate to 0 if it is not given. Decoding is still possible.
269         if not self.samplerate:
270             self.samplerate = 0
271
272         # Throw away first two edges as it might be mangled data.
273         self.wait({0: 'e'})
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
279
280         while True:
281             # Wait for any edge (rising or falling).
282             (data,) = self.wait({0: 'e'})
283             self.pulse_width = self.samplenum - self.samplenum_prev_edge
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()