Beispiel #1
0
    def test_find_symbol_rate(self):
        self.test_name = 'find_symbol_rate() test'
        self.trial_count = 40
        for i in xrange(self.trial_count):
            self.update_progress(i+1)

            freq = random.randrange(100, 10000)
            
            # construct a list of edges with random spans
            e = []
            t = 0.0
            for _ in xrange(200):
                n = random.randrange(1, 5)
                t += n / freq
                e.append((t,1)) # we maintain state at constant 1 since find_symbol_rate() doesn't care
            
            spectra = random.randrange(2, 5)

            for s in xrange(spectra, 1, -1):
                detected_rate = decode.find_symbol_rate(iter(e), spectra=s)
                if detected_rate > 0:
                    break
            
            # assertAlmostEqual() can't evaluate the closeness of two integers
            # since it doesn't incorporate relative error
            equal = tsup.relativelyEqual(detected_rate, freq, epsilon=0.01)
            # print('sr', detected_rate, freq, equal)

            if not equal:
                print('  num spectra:', spectra)
                print(e)
                
            self.assertTrue(equal, msg='symbol rate mismatch {0} != {1}'.format(detected_rate, freq))
    def __init__(self, channels, timescale=1.0e-12, date=None, comment=None):
        '''
        channels (sequence of VCDChannel)
            A sequence of channel definitions

        timescale (float or string)
            Set the VCD timescale as a power of 10.
            If a float, the value is used to establish the timescale.
            If a string, it must match a channel name from channels. The symbol rate
            of the named channel is determined and a raw timescale is derived from
            1.0 / (4 * symbol rate). In both cases the raw value will be coerced to
            a valid power of 10.

        date (datetime or None)
            An optional datetime for the VCD header. If absent the current time is used.

        comment (string or None)
            An optional comment to include in the header.

        Raises ValueError if the timescale channel cannot be found or the symbol rate cannot
          be determined.
        '''
        self._date = date
        self.comment = comment
        self.channels = channels

        try:
            ts = float(timescale)
        except ValueError:  # Assume it's a string
            # Find channel name in channels
            ts_data = None
            for c in self.channels:
                if c.name == timescale:
                    ts_data = c.states
                    break

            if ts_data is not None:
                sym_rate = decode.find_symbol_rate(iter(ts_data))
                if sym_rate == 0:
                    raise ValueError('Unable to determine automatic timescale')

                ts = 1.0 / (4 * sym_rate)
            else:
                raise ValueError('Channel not found: "{}"'.format(timescale))

        self._timescale = coerce_timescale(ts)
Beispiel #3
0
    def __init__(self, channels, timescale=1.0e-12, date=None, comment=None):
        '''
        channels (sequence of VCDChannel)
            A sequence of channel definitions

        timescale (float or string)
            Set the VCD timescale as a power of 10.
            If a float, the value is used to establish the timescale.
            If a string, it must match a channel name from channels. The symbol rate
            of the named channel is determined and a raw timescale is derived from
            1.0 / (4 * symbol rate). In both cases the raw value will be coerced to
            a valid power of 10.

        date (datetime or None)
            An optional datetime for the VCD header. If absent the current time is used.

        comment (string or None)
            An optional comment to include in the header.

        Raises ValueError if the timescale channel cannot be found or the symbol rate cannot
          be determined.
        '''
        self._date = date
        self.comment = comment
        self.channels = channels

        try:
            ts = float(timescale)
        except ValueError: # Assume it's a string
            # Find channel name in channels
            ts_data = None
            for c in self.channels:
                if c.name == timescale:
                    ts_data = c.states
                    break

            if ts_data is not None:
                sym_rate = decode.find_symbol_rate(iter(ts_data))
                if sym_rate == 0:
                    raise ValueError('Unable to determine automatic timescale')

                ts = 1.0 / (4 * sym_rate)
            else:
                raise ValueError('Channel not found: "{}"'.format(timescale))

        self._timescale = coerce_timescale(ts)
Beispiel #4
0
    def test_find_symbol_rate(self):
        self.test_name = 'find_symbol_rate() test'
        self.trial_count = 40
        for i in xrange(self.trial_count):
            self.update_progress(i + 1)

            freq = random.randrange(100, 10000)

            # construct a list of edges with random spans
            e = []
            t = 0.0
            for _ in xrange(200):
                n = random.randrange(1, 5)
                t += n / freq
                e.append(
                    (t, 1)
                )  # we maintain state at constant 1 since find_symbol_rate() doesn't care

            spectra = random.randrange(2, 5)

            for s in xrange(spectra, 1, -1):
                detected_rate = decode.find_symbol_rate(iter(e), spectra=s)
                if detected_rate > 0:
                    break

            # assertAlmostEqual() can't evaluate the closeness of two integers
            # since it doesn't incorporate relative error
            equal = tsup.relativelyEqual(detected_rate, freq, epsilon=0.01)
            # print('sr', detected_rate, freq, equal)

            if not equal:
                print('  num spectra:', spectra)
                print(e)

            self.assertTrue(equal,
                            msg='symbol rate mismatch {0} != {1}'.format(
                                detected_rate, freq))
Beispiel #5
0
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
Beispiel #6
0
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