def test_find_multi_edges(self): self.test_name = 'find_multi_edges() test' self.trial_count = 100 for i in xrange(self.trial_count): self.update_progress(i+1) bit_period = 1.0 sample_rate = bit_period * 1000 rt = sigp.min_rise_time(sample_rate) * random.uniform(20.0, 200.0) num_states = random.randint(2, 7) offset = (2 * (num_states - 1)) // 4 logic_states = (0 - offset, num_states - 1 - offset) #print('\nlogic states:', logic_states, num_states) # Generate random edges prev_state = 0 state = 0 edges = [] t = 0.0 for _ in xrange(10): while state == prev_state: # Guarantee that each edge is different from the previous state = random.randint(logic_states[0], logic_states[-1]) prev_state = state edges.append((t, state)) t += bit_period # Duplicate the last edge so that it will be decoded edges = edges + [(edges[-1][0] + bit_period, edges[-1][1])] #print('## edges:', edges) samples = sigp.synth_wave(iter(edges), sample_rate, rt, logic_states=logic_states) # Generate logic levels in range [0.0, 1.0] logic_levels = [float(level) / (num_states-1) for level in xrange(num_states)] #print('## logic_levels:', logic_levels) found_edges = list(decode.find_multi_edges(samples, decode.gen_hyst_thresholds(logic_levels))) #print('## found:', found_edges) # Remove brief transitional states that last less than half the bit period rts_edges = list(decode.remove_transitional_states(iter(found_edges), bit_period * 0.5)) #print('\n## RTS edges:', rts_edges) edges = edges[:-1] # Trim off last (duplicate) edge self.assertEqual(len(edges), len(rts_edges), msg='Mismatch in found edge count {} != {}'.format(len(edges), len(rts_edges))) for i, (e, f) in enumerate(zip(edges, rts_edges)): self.assertRelativelyEqual(e[0], f[0], epsilon=0.5, msg='Edge times not close enough {} != {}'.format(e[0], f[0])) self.assertEqual(e[1], f[1], msg='Edges not the same index={}, edge={}, found={}'.format(i, e[1], f[1]))
def test_multi_edge_finding(self): if ripyl.config.settings.cython_active: iterations = 100 cy_status = 'enabled' else: iterations = 10 cy_status = 'disabled' print('\nDetermining multi-level edge processing rate (Cython is {}, {} iterations)...'.format(cy_status, iterations)) edge_count = 1000 states = [-1, 0, 1] * (edge_count // 2) period = 1.0 intervals = [random.randint(1,15) * period for _ in xrange(len(states))] t = 0.0 edges = [(t, states[0])] for i in xrange(len(states)): t += intervals[i] edges.append((t, states[i])) sample_rate = 20 / period samples = list(sigp.synth_wave(iter(edges), sample_rate, sigp.min_rise_time(sample_rate) * 6.0, \ logic_states=(-1, 1), chunk_size=10000)) hyst_thresh = decode.gen_hyst_thresholds((0.0, 0.5, 1.0), hysteresis=0.4) self._t_start = time.time() for _ in xrange(iterations): d_edges = list(decode.find_multi_edges(iter(samples), hyst_thresh)) samples_processed = iterations * (t * sample_rate) #print('### samples:', samples_processed, int(t * sample_rate)) return (iterations, samples_processed, 'samples')
def test_find_multi_edges(self): self.test_name = 'find_multi_edges() test' self.trial_count = 100 for i in xrange(self.trial_count): self.update_progress(i + 1) bit_period = 1.0 sample_rate = bit_period * 1000 rt = sigp.min_rise_time(sample_rate) * random.uniform(20.0, 200.0) num_states = random.randint(2, 7) offset = (2 * (num_states - 1)) // 4 logic_states = (0 - offset, num_states - 1 - offset) #print('\nlogic states:', logic_states, num_states) # Generate random edges prev_state = 0 state = 0 edges = [] t = 0.0 for _ in xrange(10): while state == prev_state: # Guarantee that each edge is different from the previous state = random.randint(logic_states[0], logic_states[-1]) prev_state = state edges.append((t, state)) t += bit_period # Duplicate the last edge so that it will be decoded edges = edges + [(edges[-1][0] + bit_period, edges[-1][1])] #print('## edges:', edges) samples = sigp.synth_wave(iter(edges), sample_rate, rt, logic_states=logic_states) # Generate logic levels in range [0.0, 1.0] logic_levels = [ float(level) / (num_states - 1) for level in xrange(num_states) ] #print('## logic_levels:', logic_levels) found_edges = list( decode.find_multi_edges( samples, decode.gen_hyst_thresholds(logic_levels))) #print('## found:', found_edges) # Remove brief transitional states that last less than half the bit period rts_edges = list( decode.remove_transitional_states(iter(found_edges), bit_period * 0.5)) #print('\n## RTS edges:', rts_edges) edges = edges[:-1] # Trim off last (duplicate) edge self.assertEqual( len(edges), len(rts_edges), msg='Mismatch in found edge count {} != {}'.format( len(edges), len(rts_edges))) for i, (e, f) in enumerate(zip(edges, rts_edges)): self.assertRelativelyEqual( e[0], f[0], epsilon=0.5, msg='Edge times not close enough {} != {}'.format( e[0], f[0])) self.assertEqual( e[1], f[1], msg='Edges not the same index={}, edge={}, found={}'. format(i, e[1], f[1]))
def ethernet_decode(rxtx, tag_ethertypes=None, logic_levels=None, stream_type=stream.StreamType.Samples): '''Decode an ethernet data stream This is a generator function that can be used in a pipeline of waveform procesing operations. Sample streams are a sequence of SampleChunk Objects. Edge streams are a sequence of 2-tuples of (time, int) pairs. The type of stream is identified by the stream_type parameter. Sample streams will be analyzed to find edge transitions representing 0 and 1 logic states of the waveforms. With sample streams, an initial block of data is consumed to determine the most likely logic levels in the signal. rxtx (iterable of SampleChunk objects or (float, int) pairs) A sample stream or edge stream representing a differential ethernet signal. tag_ethertypes (sequence of int or None) The ethertypes to use for identifying 802.1Q tags. Default is 0x8100, 0x88a8, and 0x9100. logic_levels ((float, float) or None) Optional pair that indicates (low, high) logic levels of the sample stream. When present, auto level detection is disabled. This has no effect on edge streams. stream_type (streaming.StreamType) A StreamType value indicating that the can parameter represents either Samples or Edges Yields a series of EthernetStreamFrame objects. Each frame contains subrecords marking the location of sub-elements within the frame. CRC errors are recorded as an error status in their respective subrecords. Raises AutoLevelError if stream_type = Samples and the logic levels cannot be determined. Raises StreamError if ethernet speed cannot be determined. ''' if stream_type == stream.StreamType.Samples: if logic_levels is None: s_rxtx_it, logic_levels = decode.check_logic_levels(rxtx) else: s_rxtx_it = rxtx hyst_thresholds = decode.gen_hyst_thresholds(logic_levels, expand=3, hysteresis=0.05) rxtx_it = decode.find_multi_edges(s_rxtx_it, hyst_thresholds) #print('## logic levels:', logic_levels, hyst_thresholds) else: # The streams are already lists of edges rxtx_it = rxtx # Detect speed of ethernet buf_edges = 150 min_edges = 100 # tee off an iterator to determine speed class rxtx_it, speed_check_it = itertools.tee(rxtx_it) # Remove Diff-0's #FIX: need to modify to work with 100Mb and 1Gb Enet speed_check_it = (edge for edge in speed_check_it if edge[1] != 0) symbol_rate_edges = itertools.islice(speed_check_it, buf_edges) # We need to ensure that we can pull out enough edges from the iterator slice # Just consume them all for a count sre_list = list(symbol_rate_edges) if len(sre_list) < min_edges: raise stream.StreamError( 'Unable to determine Ethernet speed (not enough edge transitions)') del speed_check_it #print('## sym. rate edges len:', len(sre_list)) raw_symbol_rate = decode.find_symbol_rate(iter(sre_list), spectra=2) #print('### raw sym rate:', raw_symbol_rate) # For 10baseT (10MHz Manchester) the symbol rate will be 20MHz # For 100BaseTX the symbol rate will be 31.25MHz? if raw_symbol_rate < 25e6: bit_period = 1.0 / 10.0e6 else: raise stream.StreamError('Unsupported Ethernet speed: {}'.format( eng_si(raw_symbol_rate, 'Hz'))) if stream_type == stream.StreamType.Samples: # We needed the bus speed before we could properly strip just # the anomalous SE0s min_se0 = bit_period * 0.2 rxtx_it = decode.remove_transitional_states(rxtx_it, min_se0) mstates = manchester_decode(rxtx_it, bit_period) for r in _ethernet_generic_decode(mstates, tag_ethertypes=tag_ethertypes): yield r
def ethernet_decode(rxtx, tag_ethertypes=None, logic_levels=None, stream_type=stream.StreamType.Samples): '''Decode an ethernet data stream This is a generator function that can be used in a pipeline of waveform procesing operations. Sample streams are a sequence of SampleChunk Objects. Edge streams are a sequence of 2-tuples of (time, int) pairs. The type of stream is identified by the stream_type parameter. Sample streams will be analyzed to find edge transitions representing 0 and 1 logic states of the waveforms. With sample streams, an initial block of data is consumed to determine the most likely logic levels in the signal. rxtx (iterable of SampleChunk objects or (float, int) pairs) A sample stream or edge stream representing a differential ethernet signal. tag_ethertypes (sequence of int or None) The ethertypes to use for identifying 802.1Q tags. Default is 0x8100, 0x88a8, and 0x9100. logic_levels ((float, float) or None) Optional pair that indicates (low, high) logic levels of the sample stream. When present, auto level detection is disabled. This has no effect on edge streams. stream_type (streaming.StreamType) A StreamType value indicating that the can parameter represents either Samples or Edges Yields a series of EthernetStreamFrame objects. Each frame contains subrecords marking the location of sub-elements within the frame. CRC errors are recorded as an error status in their respective subrecords. Raises AutoLevelError if stream_type = Samples and the logic levels cannot be determined. Raises StreamError if ethernet speed cannot be determined. ''' if stream_type == stream.StreamType.Samples: if logic_levels is None: s_rxtx_it, logic_levels = decode.check_logic_levels(rxtx) else: s_rxtx_it = rxtx hyst_thresholds = decode.gen_hyst_thresholds(logic_levels, expand=3, hysteresis=0.05) rxtx_it = decode.find_multi_edges(s_rxtx_it, hyst_thresholds) #print('## logic levels:', logic_levels, hyst_thresholds) else: # The streams are already lists of edges rxtx_it = rxtx # Detect speed of ethernet buf_edges = 150 min_edges = 100 # tee off an iterator to determine speed class rxtx_it, speed_check_it = itertools.tee(rxtx_it) # Remove Diff-0's #FIX: need to modify to work with 100Mb and 1Gb Enet speed_check_it = (edge for edge in speed_check_it if edge[1] != 0) symbol_rate_edges = itertools.islice(speed_check_it, buf_edges) # We need to ensure that we can pull out enough edges from the iterator slice # Just consume them all for a count sre_list = list(symbol_rate_edges) if len(sre_list) < min_edges: raise stream.StreamError('Unable to determine Ethernet speed (not enough edge transitions)') del speed_check_it #print('## sym. rate edges len:', len(sre_list)) raw_symbol_rate = decode.find_symbol_rate(iter(sre_list), spectra=2) #print('### raw sym rate:', raw_symbol_rate) # For 10baseT (10MHz Manchester) the symbol rate will be 20MHz # For 100BaseTX the symbol rate will be 31.25MHz? if raw_symbol_rate < 25e6: bit_period = 1.0 / 10.0e6 else: raise stream.StreamError('Unsupported Ethernet speed: {}'.format(eng_si(raw_symbol_rate, 'Hz'))) if stream_type == stream.StreamType.Samples: # We needed the bus speed before we could properly strip just # the anomalous SE0s min_se0 = bit_period * 0.2 rxtx_it = decode.remove_transitional_states(rxtx_it, min_se0) mstates = manchester_decode(rxtx_it, bit_period) for r in _ethernet_generic_decode(mstates, tag_ethertypes=tag_ethertypes): yield r