Пример #1
0
 def data_ok(self, check, want_len):
     name = self.state.title()
     normal, inverted = bitpack(self.data[:8]), bitpack(self.data[8:])
     valid = (normal ^ inverted) == 0xff
     show = inverted if self.state.endswith('#') else normal
     is_ext_addr = self.is_extended and self.state == 'ADDRESS'
     if is_ext_addr:
         normal = bitpack(self.data)
         show = normal
         valid = True
     if len(self.data) == want_len:
         if self.state == 'ADDRESS':
             self.addr = normal
         if self.state == 'COMMAND':
             self.cmd = normal
         self.putd(show, want_len)
         self.ss_start = self.samplenum
         if is_ext_addr:
             self.data = []
             self.ss_bit = self.ss_start = self.samplenum
         return True
     self.putd(show, want_len)
     if check and not valid:
         warn_show = bitpack(self.data)
         self.putx(
             [Ann.WARN, ['{} error: 0x{:04X}'.format(name, warn_show)]])
     self.data = []
     self.ss_bit = self.ss_start = self.samplenum
     return valid
Пример #2
0
    def decode(self):
        chmask = [self.has_channel(i) for i in range(MAX_CHANNELS)]
        self.num_channels = sum(chmask)
        if chmask != [i < self.num_channels for i in range(MAX_CHANNELS)]:
            raise ChannelMapError('Assigned channels need to be contiguous')

        self.ENCODER_STEPS = 1 << self.num_channels

        (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait()
        startbits = (d0, d1, d2, d3, d4, d5, d6, d7)
        curtime = self.samplenum

        self.turns.set(self.samplenum, 0)
        self.count.set(self.samplenum, 0)
        self.phase.set(self.samplenum, gray_decode(bitpack(startbits[:self.num_channels])))

        while True:
            prevtime = curtime
            (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait([{i: 'e'} for i in range(self.num_channels)])
            bits = (d0, d1, d2, d3, d4, d5, d6, d7)
            curtime = self.samplenum

            oldcount = self.count.get()
            oldphase = self.phase.get()

            newphase = gray_decode(bitpack(bits[:self.num_channels]))
            self.phase.set(self.samplenum, newphase)

            phasedelta_raw = (newphase - oldphase + (self.ENCODER_STEPS // 2 - 1)) % self.ENCODER_STEPS - (self.ENCODER_STEPS // 2 - 1)
            phasedelta = phasedelta_raw
            self.increment.set(self.samplenum, phasedelta)
            if abs(phasedelta) == self.ENCODER_STEPS // 2:
                phasedelta = 0

            self.count.set(self.samplenum, self.count.get() + phasedelta)

            if self.options['edges']:
                self.turns.set(self.samplenum, self.count.get() // self.options['edges'])

            if self.samplerate:
                period = (curtime - prevtime) / self.samplerate
                freq = abs(phasedelta_raw) / period

                self.put(prevtime, curtime, self.out_ann, [4, [
                    '{}s, {}Hz'.format(prefix_fmt(period), prefix_fmt(freq))]])

                if self.options['avg_period']:
                    self.last_n.append((abs(phasedelta_raw), period))
                    if len(self.last_n) > self.options['avg_period']:
                        self.last_n.popleft()

                    avg_period = sum(v for u, v in self.last_n) / (sum(u for u, v in self.last_n) or 1)
                    self.put(prevtime, curtime, self.out_ann, [5, [
                        '{}s, {}Hz'.format(prefix_fmt(avg_period),
                            prefix_fmt(1 / avg_period))]])

                if self.options['edges']:
                    self.put(prevtime, curtime, self.out_ann, [6, ['{}rpm'.format(prefix_fmt(60 * freq / self.options['edges'], emin=0))]])
Пример #3
0
    def handle_header(self):
        if len(self.bits) == 1:
            self.ss_header = self.ss_bit

        if len(self.bits) == 8:
            # See tc27xD_um_v2.2.pdf, Figure 20-47, for the header structure
            bit_len = (self.es_bit - self.ss_header) / 8
            value = bitpack(self.bits)

            ss = self.ss_header
            es = ss + 3 * bit_len
            size_id = (value & 0xE0) >> 5
            size = payload_sizes.get(size_id)
            self.payload_size = payload_byte_sizes.get(size_id)
            self.put_ann(int(ss), int(es), ann_header_pl_size, [size])

            ss = es
            es = ss + 4 * bit_len
            self.ch_type_id = (value & 0x1E) >> 1
            ch_type = channel_types.get(self.ch_type_id)
            self.put_ann(int(ss), int(es), ann_header_ch_type, [ch_type])

            ss = es
            es = ss + bit_len
            cts = value & 0x01
            self.put_ann(int(ss), int(es), ann_header_cts, ['{}'.format(cts)])

            self.bits = []
            self.state = state_payload
            self.timeout = int(9.4 * self.bit_len)
Пример #4
0
    def handle_payload(self):
        self.timeout = int(
            (self.payload_size - len(self.payload)) * 8 * self.bit_len)

        if len(self.bits) == 1:
            self.ss_byte = self.ss_bit
            if self.ss_payload == 0:
                self.ss_payload = self.ss_bit

        if len(self.bits) == 8:
            value = bitpack(self.bits)
            value_hex = '{:02X}'.format(value)

            # Control transfers have no SIPI payload, show them as control transfers
            # Check the channel_types list for the meaning of the magic values
            if (self.ch_type_id >= 0b0100) and (self.ch_type_id <= 0b1011):
                self.put_ann(self.ss_byte, self.es_bit, ann_payload,
                             [value_hex])
            else:
                # Control transfers are 8-bit transfers, so only evaluate the first byte
                if len(self.payload) == 0:
                    ctrl_data = control_payloads.get(value, value_hex)
                    self.put_ann(self.ss_byte, self.es_bit, ann_control_data,
                                 [ctrl_data])
                else:
                    self.put_ann(self.ss_byte, self.es_bit, ann_control_data,
                                 [value_hex])

            self.bits = []
            self.es_payload = self.es_bit
            self.payload.append((self.ss_byte, self.es_payload, value))

            if (len(self.payload) == self.payload_size):
                self.timeout = int(1.4 * self.bit_len)
                self.state = state_sleepbit
Пример #5
0
    def get_data_bits(self, signal):
        # Save the sample number of the middle of the first data bit.
        if self.startsample == -1:
            self.startsample = self.samplenum

        # Store individual data bits and their start/end samplenumbers.
        s, halfbit = self.samplenum, int(self.bit_width / 2)
        self.databits.append([signal, s - halfbit, s + halfbit])

        # Return here, unless we already received all data bits.
        self.cur_data_bit += 1
        if self.cur_data_bit < self.options['num_data_bits']:
            return

        # Convert accumulated data bits to a data value.
        bits = [b[0] for b in self.databits]
        if self.options['bit_order'] == 'msb-first':
            bits.reverse()
        self.datavalue = bitpack(bits)

        b = self.datavalue
        formatted = self.format_value(b)
        if formatted is not None:
            self.putx([0, [formatted]])

        self.databits = []

        # Advance to either reception of the parity bit, or reception of
        # the STOP bits if parity is not applicable.
        self.state = 'GET PARITY BIT'
        if self.options['parity_type'] == 'none':
            self.state = 'GET STOP BITS'
Пример #6
0
    def grab_pattern(self, pins):
        '''Get a bit pattern from potentially incomplete probes' values.'''

        # Pad and trim the input data, to achieve the user specified
        # total number of bits. Map all unassigned signals to 0 (low).
        # Return raw number (unsigned integer interpreation).
        bits = pins + (None, ) * self.bitcount
        bits = bits[:self.bitcount]
        bits = [b if b in (0, 1) else 0 for b in bits]
        pattern = bitpack(bits)
        return pattern
Пример #7
0
 def inject_dav_phase(self, ss, es, data):
     # Inspection of serial input has resulted in one raw byte which
     # spans a given period of time. Pretend we had seen a DAV active
     # phase, to re-use code for the parallel transmission.
     self.ss_raw = ss
     self.curr_raw = bitpack(data)
     self.latch_atn = self.curr_atn
     self.latch_eoi = self.curr_eoi
     self.es_raw = es
     self.handle_data_byte()
     self.ss_raw = self.es_raw = None
     self.curr_raw = None
Пример #8
0
    def decode_pins(self, pins, idx_strip):
        bits = [0 if idx is None else pins[idx] for idx in self.idx_channels]
        item = bitpack(bits[0:idx_strip])

        item = (item >> self.left) & self.mask

        if not self.first:
            if item != self.last_item:
                self.put(self.ss_item, self.samplenum, self.out_python, [self.last_item, self.length])
                self.ss_item = self.samplenum
        else:
            self.ss_item = self.samplenum
        self.last_item = item
        self.first = False
Пример #9
0
 def handle_dav_change(self, dav, data):
     if dav:
         # Data availability starts when the flag goes active.
         self.ss_raw = self.samplenum
         self.curr_raw = bitpack(data)
         self.latch_atn = self.curr_atn
         self.latch_eoi = self.curr_eoi
         return
     # Data availability ends when the flag goes inactive. Handle the
     # previously captured data byte according to associated flags.
     self.es_raw = self.samplenum
     self.handle_data_byte()
     self.ss_raw = self.es_raw = None
     self.curr_raw = None
Пример #10
0
    def decode(self):
        # Determine which (optional) channels have input data. Insist in
        # a non-empty input data set. Cope with sparse connection maps.
        # Store enough state to later "compress" sampled input data.
        max_possible = len(self.optional_channels)
        idx_channels = [
            idx if self.has_channel(idx) else None
            for idx in range(max_possible)
        ]
        has_channels = [idx for idx in idx_channels if idx is not None]
        if not has_channels:
            raise ChannelError('At least one channel has to be supplied.')
        max_connected = max(has_channels)

        # Determine .wait() conditions, depending on the presence of a
        # clock signal. Either inspect samples on the configured edge of
        # the clock, or inspect samples upon ANY edge of ANY of the pins
        # which provide input data.
        if self.has_channel(0):
            edge = self.options['clock_edge'][0]
            conds = {0: edge}
        else:
            conds = [{idx: 'e'} for idx in has_channels]

        # Pre-determine which input data to strip off, the width of
        # individual items and multiplexed words, as well as format
        # strings here. This simplifies call sites which run in tight
        # loops later.
        idx_strip = max_connected + 1
        num_item_bits = idx_strip - 1
        num_word_items = self.options['wordsize']
        num_word_bits = num_item_bits * num_word_items
        num_digits = (num_item_bits + 3) // 4
        self.fmt_item = "{{:0{}x}}".format(num_digits)
        num_digits = (num_word_bits + 3) // 4
        self.fmt_word = "{{:0{}x}}".format(num_digits)

        # Keep processing the input stream. Assume "always zero" for
        # not-connected input lines. Pass data bits (all inputs except
        # clock) to the handle_bits() method.
        while True:
            (clk, d0, d1, d2, d3, d4, d5, d6, d7) = self.wait(conds)
            pins = (clk, d0, d1, d2, d3, d4, d5, d6, d7)
            bits = [0 if idx is None else pins[idx] for idx in idx_channels]
            item = bitpack(bits[1:idx_strip])
            self.handle_bits(item, num_item_bits)
Пример #11
0
    def handle_sync(self):
        if len(self.bits) == 1:
            self.ss_sync = self.ss_bit

        if len(self.bits) == 16:
            value = bitpack(self.bits)
            if value == 0xA84B:
                self.put_ann(self.ss_sync, self.es_bit, ann_sync, ['Sync OK'])
            else:
                self.put_ann(self.ss_sync, self.es_bit, ann_warning,
                             ['Wrong Sync Value: {:02X}'.format(value)])
                self.reset()

            # Only continue if we didn't just reset
            if self.ss > 0:
                self.bits = []
                self.state = state_header
                self.timeout = int(9.4 * self.bit_len)
Пример #12
0
    def get_data_bits(self, rxtx, signal):
        # Save the sample number of the middle of the first data bit.
        if self.startsample[rxtx] == -1:
            self.startsample[rxtx] = self.samplenum

        self.putg([rxtx + 12, ['%d' % signal]])

        # Store individual data bits and their start/end samplenumbers.
        s, halfbit = self.samplenum, int(self.bit_width / 2)
        self.databits[rxtx].append([signal, s - halfbit, s + halfbit])

        # Return here, unless we already received all data bits.
        self.cur_data_bit[rxtx] += 1
        if self.cur_data_bit[rxtx] < self.options['data_bits']:
            return

        # Convert accumulated data bits to a data value.
        bits = [b[0] for b in self.databits[rxtx]]
        if self.options['bit_order'] == 'msb-first':
            bits.reverse()
        self.datavalue[rxtx] = bitpack(bits)
        self.putpx(rxtx, ['DATA', rxtx,
            (self.datavalue[rxtx], self.databits[rxtx])])

        b = self.datavalue[rxtx]
        formatted = self.format_value(b)
        if formatted is not None:
            self.putx(rxtx, [rxtx, [formatted]])

        bdata = b.to_bytes(self.bw, byteorder='big')
        self.putbin(rxtx, [rxtx, bdata])
        self.putbin(rxtx, [2, bdata])

        self.handle_packet(rxtx)

        self.databits[rxtx] = []

        # Advance to either reception of the parity bit, or reception of
        # the STOP bits if parity is not applicable.
        self.state[rxtx] = 'GET PARITY BIT'
        if self.options['parity'] == 'none':
            self.state[rxtx] = 'GET STOP BITS'
Пример #13
0
 def frame_flush(self):
     syms = self.symbols_clear()
     while syms and syms[0][2] == 'IDLE':
         syms.pop(0)
     while syms and syms[-1][2] == 'IDLE':
         syms.pop(-1)
     if not syms:
         return
     text = []
     data = []
     for sym in syms:
         if sym[2] == 'FRAME_INIT':
             text.append('INIT')
             data.append('INIT')
             continue
         if sym[2] == 'SYNC_PAD':
             if not text or text[-1] != 'SYNC':
                 text.append('SYNC')
                 data.append('SYNC')
             continue
         if sym[2] == 'DATA_BYTE':
             b = [bit[3] for bit in sym[3] if bit[2] == 'DATA_BIT']
             b = bitpack(b)
             text.append('{:02x}'.format(b))
             data.append(b)
             continue
         if sym[2] == 'SHORT_BIT':
             if not text or text[-1] != 'SHORT':
                 text.append('SHORT')
                 data.append('SHORT')
             continue
         if sym[2] == 'WAIT_ACK':
             text.append('WAIT')
             data.append('WAIT')
             continue
     text = ' '.join(text)
     ss, es = syms[0][0], syms[-1][1]
     self.putg(ss, es, [ANN_FRAME_BYTES, [text]])
     self.putpy(ss, es, 'FRAME_DATA', data)
Пример #14
0
    def get_data_bits(self, rxtx, signal):
        # Save the sample number of the middle of the first data bit.
        if self.startsample[rxtx] == -1:
            self.startsample[rxtx] = self.samplenum

        self.putg([Ann.RX_DATA_BIT + rxtx, ['%d' % signal]])

        # Store individual data bits and their start/end samplenumbers.
        s, halfbit = self.samplenum, int(self.bit_width / 2)
        self.databits[rxtx].append([signal, s - halfbit, s + halfbit])
        self.cur_frame_bit[rxtx] += 1

        # Return here, unless we already received all data bits.
        self.cur_data_bit[rxtx] += 1
        if self.cur_data_bit[rxtx] < self.options['data_bits']:
            return

        # Convert accumulated data bits to a data value.
        bits = [b[0] for b in self.databits[rxtx]]
        if self.options['bit_order'] == 'msb-first':
            bits.reverse()
        self.datavalue[rxtx] = bitpack(bits)
        self.putpx(rxtx,
                   ['DATA', rxtx, (self.datavalue[rxtx], self.databits[rxtx])])

        b = self.datavalue[rxtx]
        formatted = self.format_value(b)
        if formatted is not None:
            self.putx(rxtx, [rxtx, [formatted]])

        bdata = b.to_bytes(self.bw, byteorder='big')
        self.putbin(rxtx, [Bin.RX + rxtx, bdata])
        self.putbin(rxtx, [Bin.RXTX, bdata])

        self.handle_packet(rxtx)

        self.databits[rxtx] = []

        self.advance_state(rxtx, signal)
Пример #15
0
    def decode(self):
        if not self.samplerate or self.samplerate < 1e6:
            raise SamplerateError('Need a samplerate of at least 1MSa/s')

        # As a special case the first low period in the input capture is
        # saught regardless of whether we can see its falling edge. This
        # approach is also used to recover after synchronization was lost.
        #
        # The important condition here in the main loop is: Get the next
        # edge's position, but time out after a maximum period of four
        # data bits. This allows for the detection of SYNC pulses, also
        # responds "soon enough" to DATA bits where edges can be few
        # within a data byte. Also avoids excessive waits for unexpected
        # communication errors.
        #
        # DATA bits within a byte are taken at fixed intervals relative
        # to the SYNC-PAD's falling edge. It's essential to check the
        # carrier at every edge, also during DATA bit sampling. Simple
        # skips to the desired sample point could break that feature.
        while True:

            # Help kick-start the IDLE condition detection after
            # decoder state reset.
            if not self.edges:
                curr_level, = self.wait({PIN_DATA: 'l'})
                self.carrier_check(curr_level, self.samplenum)
                self.edges = [self.samplenum]
                continue

            # Advance to the next edge, or over a medium span without an
            # edge. Prepare to classify the distance to derive bit types
            # from these details.
            last_snum = self.samplenum
            curr_level, = self.wait([{
                PIN_DATA: 'e'
            }, {
                'skip': self.lookahead_width
            }])
            self.carrier_check(curr_level, self.samplenum)
            bit_level = curr_level
            edge_seen = self.matched[0]
            if edge_seen:
                bit_level = 1 - bit_level
            if not self.edges:
                self.edges = [self.samplenum]
                continue
            self.edges.append(self.samplenum)
            curr_snum = self.samplenum

            # Check bit width (can also be multiple data bits).
            span = self.edges[-1] - self.edges[-2]
            is_pad = bit_level and self.span_is_pad(span)
            is_data = self.span_is_data(span)
            is_short = bit_level and self.span_is_short(span)

            if is_pad:
                # BEWARE! Use ss value of last edge (genuinely seen, or
                # inserted after a DATA byte) for PAD bit annotations.
                ss, es = self.edges[-2], curr_snum
                texts = ['PAD', '{:d}'.format(bit_level)]
                self.putg(ss, es, [ANN_PAD_BIT, texts])
                self.symbols_append(ss, es, 'PAD_BIT', bit_level)
                ss, es = self.symbols_get_last()[:2]
                self.putpy(ss, es, 'PAD_BIT', bit_level)
                continue

            if is_short:
                ss, es = last_snum, curr_snum
                texts = ['SHORT', '{:d}'.format(bit_level)]
                self.putg(ss, es, [ANN_SHORT_DATA, texts])
                self.symbols_append(ss, es, 'SHORT_BIT', bit_level)
                ss, es = self.symbols_get_last()[:2]
                self.putpy(ss, es, 'SHORT_BIT', bit_level)
                continue

            # Force IDLE period check when the decoder seeks to sync
            # to the input data stream.
            if not bit_level and not self.symbols and self.carrier_want_idle:
                continue

            # Accept arbitrary length LOW phases after DATA bytes(!) or
            # SHORT pulses, but not within a DATA byte or SYNC-PAD etc.
            # This covers the late start of the next SYNC-PAD (byte of
            # a frame, or ACK byte after a frame, or the start of the
            # next frame).
            if not bit_level:
                if self.symbols_has_prev('DATA_BYTE'):
                    continue
                if self.symbols_has_prev('SHORT_BIT'):
                    continue
                if self.symbols_has_prev('WAIT_ACK'):
                    continue

            # Get (consume!) the LOW DATA bit after a PAD.
            took_low = False
            if is_data and not bit_level and self.symbols_has_prev('PAD_BIT'):
                took_low = True
                is_data -= 1
                next_snum = int(last_snum + self.data_width)
                ss, es = last_snum, next_snum
                texts = ['ZERO', '{:d}'.format(bit_level)]
                self.putg(ss, es, [ANN_LOW_BIT, texts])
                self.symbols_append(ss, es, 'ZERO_BIT', bit_level)
                ss, es = self.symbols_get_last()[:2]
                self.putpy(ss, es, 'DATA_BIT', bit_level)
                self.data_fall_time = last_snum
                last_snum = next_snum
            # Turn the combination of PAD and LOW DATA into SYNC-PAD.
            # Start data bit accumulation after a SYNC-PAD was seen.
            sync_pad_seq = ['PAD_BIT', 'ZERO_BIT']
            if self.symbols_has_prev(sync_pad_seq):
                self.symbols_collapse(len(sync_pad_seq), 'SYNC_PAD')
                ss, es = self.symbols_get_last()[:2]
                self.putpy(ss, es, 'SYNC_PAD', True)
                self.data_bits = []
            # Turn three subsequent SYNC-PAD into FRAME-INIT. Start the
            # accumulation of frame bytes when FRAME-INIT was seen.
            frame_init_seq = 3 * ['SYNC_PAD']
            if self.symbols_has_prev(frame_init_seq):
                self.symbols_collapse(len(frame_init_seq), 'FRAME_INIT')
                # Force a flush of the previous frame after we have
                # reliably detected the start of another one. This is a
                # workaround for this decoder's inability to detect the
                # end of a frame after an ACK was seen or byte counts
                # have been reached. We cannot assume perfect input,
                # thus we leave all interpretation of frame content to
                # upper layers. Do keep the recently queued FRAME_INIT
                # symbol across the flush operation.
                if len(self.symbols) > 1:
                    keep = self.symbols.pop(-1)
                    self.frame_flush()
                    self.symbols.clear()
                    self.symbols.append(keep)
                ss, es = self.symbols_get_last()[:2]
                texts = ['FRAME INIT', 'INIT', 'I']
                self.putg(ss, es, [ANN_FRAME_INIT, texts])
                self.putpy(ss, es, 'FRAME_INIT', True)
                self.frame_bytes = []
            # Collapse SYNC-PAD after SHORT+ into a WAIT-ACK. Include
            # all leading SHORT bits in the WAIT as well.
            wait_ack_seq = ['SHORT_BIT', 'SYNC_PAD']
            if self.symbols_has_prev(wait_ack_seq):
                self.symbols_collapse(len(wait_ack_seq),
                                      'WAIT_ACK',
                                      squeeze='SHORT_BIT')
                ss, es = self.symbols_get_last()[:2]
                texts = [
                    'WAIT for sync response', 'WAIT response', 'WAIT', 'W'
                ]
                self.putg(ss, es, [ANN_FRAME_WAIT, texts])
                self.putpy(ss, es, 'SYNC_RESP_WAIT', True)
            if took_low and not is_data:
                # Start at the very next edge if we just consumed a LOW
                # after a PAD bit, and the DATA bit count is exhausted.
                # This improves robustness, deals with inaccurate edge
                # positions. (Motivated by real world captures, the spec
                # would not discuss bit time tolerances.)
                continue

            # When we get here, the only remaining (the only supported)
            # activity is the collection of a data byte's DATA bits.
            # These are not taken by the main loop's "edge search, with
            # a timeout" approach, which is "too tolerant". Instead all
            # DATA bits get sampled at a fixed interval and relative to
            # the SYNC-PAD's falling edge. We expect to have seen the
            # data byte' SYNC-PAD before. If we haven't, the decoder is
            # not yet synchronized to the input data.
            if not is_data:
                fast_cont = edge_seen and curr_level
                ss, es = last_snum, curr_snum
                texts = ['failed pulse length check', 'pulse length', 'length']
                self.putg(ss, es, [ANN_SYNC_LOSS, texts])
                self.frame_flush()
                self.carrier_flush()
                self.reset_state()
                if fast_cont:
                    self.edges = [self.samplenum]
                continue
            if not self.symbols_has_prev('SYNC_PAD'):
                # Fast reponse to the specific combination of: no-sync,
                # edge seen, and current high level. In this case we
                # can reset internal state, but also can continue the
                # interpretation right after the most recently seen
                # rising edge, which could start the next PAD time.
                # Otherwise continue slow interpretation after reset.
                fast_cont = edge_seen and curr_level
                self.frame_flush()
                self.carrier_flush()
                self.reset_state()
                if fast_cont:
                    self.edges = [self.samplenum]
                continue

            # The main loop's "edge search with period timeout" approach
            # can have provided up to three more DATA bits after the LOW
            # bit of the SYNC-PAD. Consume them immediately in that case,
            # otherwise .wait() for their sample point. Stick with float
            # values for bit sample points and bit time boundaries for
            # improved accuracy, only round late to integers when needed.
            bit_field = []
            bit_ss = self.data_fall_time + self.data_width
            for bit_idx in range(8):
                bit_es = bit_ss + self.data_width
                bit_snum = (bit_es + bit_ss) / 2
                if bit_snum > self.samplenum:
                    bit_level, = self.wait_until(bit_snum)
                ss, es = ceil(bit_ss), floor(bit_es)
                texts = ['{:d}'.format(bit_level)]
                self.putg(ss, es, [ANN_DATA_BIT, texts])
                self.symbols_append(ss, es, 'DATA_BIT', bit_level)
                ss, es = self.symbols_get_last()[:2]
                self.putpy(ss, es, 'DATA_BIT', bit_level)
                bit_field.append(bit_level)
                if self.data_bits is not None:
                    self.data_bits.append(bit_level)
                bit_ss = bit_es
            end_snum = bit_es
            curr_level, = self.wait_until(end_snum)
            curr_snum = self.samplenum

            # We are at the exact _calculated_ boundary of the last DATA
            # bit time. Improve robustness for those situations where
            # the transmitter's and the sender's timings differ within a
            # margin, and the transmitter may hold the last DATA bit's
            # HIGH level for a little longer.
            #
            # When no falling edge is seen within the maximum tolerance
            # for the last DATA bit, then this could be the combination
            # of a HIGH DATA bit and a PAD bit without a LOW in between.
            # Fake an edge in that case, to re-use existing code paths.
            # Make sure to keep referencing times to the last SYNC pad's
            # falling edge. This is the last reliable condition we have.
            if curr_level:
                hold = self.hold_high_width
                curr_level, = self.wait([{PIN_DATA: 'l'}, {'skip': int(hold)}])
                self.carrier_check(curr_level, self.samplenum)
                if self.matched[1]:
                    self.edges.append(curr_snum)
                    curr_level = 1 - curr_level
                curr_snum = self.samplenum

            # Get the byte value from the bits (when available).
            # TODO Has the local 'bit_field' become obsolete, or should
            # self.data_bits go away?
            data_byte = bitpack(bit_field)
            if self.data_bits is not None:
                data_byte = bitpack(self.data_bits)
                self.data_bits.clear()
                if self.frame_bytes is not None:
                    self.frame_bytes.append(data_byte)

            # Turn a sequence of a SYNC-PAD and eight DATA bits into a
            # DATA-BYTE symbol.
            byte_seq = ['SYNC_PAD'] + 8 * ['DATA_BIT']
            if self.symbols_has_prev(byte_seq):
                self.symbols_collapse(len(byte_seq), 'DATA_BYTE')
                ss, es = self.symbols_get_last()[:2]
                texts = ['{:02x}'.format(data_byte)]
                self.putg(ss, es, [ANN_DATA_BYTE, texts])
                self.putpy(ss, es, 'DATA_BYTE', data_byte)

            # Optionally terminate the accumulation of a frame when a
            # WAIT-ACK period was followed by a DATA-BYTE? This could
            # flush the current packet before the next FRAME-INIT or
            # IDLE are seen, and increases usability for short input
            # data (aggressive trimming). It won't help when WAIT is
            # not seen, though.
            sync_resp_seq = ['WAIT_ACK'] + ['DATA_BYTE']
            if self.symbols_has_prev(sync_resp_seq):
                self.frame_flush()
Пример #16
0
    def decode(self):
        # Determine which (optional) channels have input data. Insist in
        # a non-empty input data set. Cope with sparse connection maps.
        # Store enough state to later "compress" sampled input data.
        data_indices = [
            idx if self.has_channel(idx) else None
            for idx in range(Pin.DATA_0, Pin.DATA_N)
        ]
        has_data = [idx for idx in data_indices if idx is not None]
        if not has_data:
            raise ChannelError('Need at least one data channel.')
        max_connected = max(has_data)

        # Pre-determine which input data to strip off, the width of
        # individual items and multiplexed words, as well as format
        # strings here. This simplifies call sites which run in tight
        # loops later.
        upper_data_bound = max_connected + 1
        num_item_bits = upper_data_bound - Pin.DATA_0
        num_word_items = self.options['wordsize']
        num_word_bits = num_item_bits * num_word_items
        num_digits = (num_item_bits + 4 - 1) // 4
        self.fmt_item = "{{:0{}x}}".format(num_digits)
        num_digits = (num_word_bits + 4 - 1) // 4
        self.fmt_word = "{{:0{}x}}".format(num_digits)

        # Determine .wait() conditions, depending on the presence of a
        # clock signal. Either inspect samples on the configured edge of
        # the clock, or inspect samples upon ANY edge of ANY of the pins
        # which provide input data.
        conds = []
        cond_idx_clock = None
        cond_idx_data_0 = None
        cond_idx_data_N = None
        cond_idx_reset = None
        has_clock = self.has_channel(Pin.CLOCK)
        if has_clock:
            cond_idx_clock = len(conds)
            edge = {
                'rising': 'r',
                'falling': 'f',
                'either': 'e',
            }.get(self.options['clock_edge'])
            conds.append({Pin.CLOCK: edge})
        else:
            cond_idx_data_0 = len(conds)
            conds.extend([{idx: 'e'} for idx in has_data])
            cond_idx_data_N = len(conds)
        has_reset = self.has_channel(Pin.RESET)
        if has_reset:
            cond_idx_reset = len(conds)
            conds.append({Pin.RESET: 'e'})
            reset_active = {
                'low-active': 0,
                'high-active': 1,
            }.get(self.options['reset_polarity'])

        # Keep processing the input stream. Assume "always zero" for
        # not-connected input lines. Pass data bits (all inputs except
        # clock and reset) to the handle_bits() method. Handle reset
        # edges first and data changes then, within the same iteration.
        # This results in robust operation for low-oversampled input.
        in_reset = False
        while True:
            pins = self.wait(conds)
            clock_edge = cond_idx_clock is not None and self.matched[
                cond_idx_clock]
            data_edge = cond_idx_data_0 is not None and [
                idx for idx in range(cond_idx_data_0, cond_idx_data_N)
                if self.matched[idx]
            ]
            reset_edge = cond_idx_reset is not None and self.matched[
                cond_idx_reset]

            if reset_edge:
                in_reset = pins[Pin.RESET] == reset_active
                if in_reset:
                    self.handle_bits(self.samplenum, None, num_item_bits)
                    self.flush_word(num_item_bits)
            if in_reset:
                continue

            if clock_edge or data_edge:
                data_bits = [
                    0 if idx is None else pins[idx] for idx in data_indices
                ]
                data_bits = data_bits[:num_item_bits]
                item = bitpack(data_bits)
                self.handle_bits(self.samplenum, item, num_item_bits)
Пример #17
0
    def decode(self):
        last_sent = None
        timeout_ms = self.options['timeout_ms']
        want_unit = self.options['unit']
        show_all = self.options['changes'] == 'no'
        wait_cond = [{0: 'r'}]
        if timeout_ms:
            snum_per_ms = self.samplerate / 1000
            timeout_snum = timeout_ms * snum_per_ms
            wait_cond.append({'skip': round(timeout_snum)})
        while True:
            # Sample data at the rising clock edge. Optionally timeout
            # after inactivity for a user specified period. Present the
            # number of unprocessed bits to the user for diagnostics.
            clk, data = self.wait(wait_cond)
            if timeout_ms and not self.matched[0]:
                if self.number_bits or self.flags_bits:
                    count = len(self.number_bits) + len(self.flags_bits)
                    self.putg(self.ss, self.samplenum, 1, [
                        'timeout with {} bits in buffer'.format(count),
                        'timeout ({} bits)'.format(count),
                        'timeout',
                    ])
                self.reset()
                continue

            # Store position of first bit and last activity.
            # Shift in measured number and flag bits.
            if not self.ss:
                self.ss = self.samplenum
            self.es = self.samplenum
            if len(self.number_bits) < 16:
                self.number_bits.append(data)
                continue
            if len(self.flags_bits) < 8:
                self.flags_bits.append(data)
                if len(self.flags_bits) < 8:
                    continue

            # Get raw values from received data bits. Run the number
            # conversion, controlled by flags and/or user specs.
            negative = bool(self.flags_bits[4])
            is_inch = bool(self.flags_bits[7])
            number = bitpack(self.number_bits)
            if negative:
                number = -number
            if is_inch:
                number /= 2000
                if want_unit == 'mm':
                    number *= mm_per_inch
                    is_inch = False
            else:
                number /= 100
                if want_unit == 'inch':
                    number = round(number / mm_per_inch, 4)
                    is_inch = True
            unit = 'in' if is_inch else 'mm'

            # Construct and emit an annotation.
            if show_all or (number, unit) != last_sent:
                self.putg(self.ss, self.es, 0, [
                    '{number}{unit}'.format(**locals()),
                    '{number}'.format(**locals()),
                ])
                last_sent = (number, unit)

            # Reset internal state for the start of the next packet.
            self.reset()
Пример #18
0
    def decode(self):

        # Wait for samples
        if not self.samplerate:
            raise SamplerateError('No input data')

        # Polarity config auto (sample 0 as reference)
        if self.options['polarity'] == 'auto':
            level, = self.wait({'skip': 0})
            active = 1 - level

        # Polarity config manual
        else:
            active = 0 if self.options['polarity'] == 'active low' else 1

        # Main
        while True:

            # Wait for pin change
            self.ri, = self.wait({Pin.RI: 'e'})

            # Pin active
            if self.ri != active:
                if self.state != 'Stop':
                    continue

            # Long idle reset
            space = self.samplenum - self.samplenum_save
            if self.state != 'Stop' and space > self.idle:
                self.reset()

            # Start bit
            if self.state == 'Idle':
                if self.tolerance(space, self.header):
                    self.put(self.samplenum_field, self.samplenum, self.anchor,
                             [Ann.BitStart, ['Start', 'S']])
                    self.put(self.samplenum_field, self.samplenum, self.anchor,
                             [Ann.Header, ['Start', 'S']])
                    self.samplenum_decode = self.samplenum_field
                    self.data = []
                    self.state = 'Code'
                self.samplenum_save = self.samplenum_field = self.samplenum

            # Code bits
            elif self.state == 'Code':
                bit = None
                if self.tolerance(space, self.lo):
                    bit = 0
                elif self.tolerance(space, self.hi):
                    bit = 1
                if bit in (0, 1):
                    self.put(self.samplenum_save, self.samplenum, self.anchor,
                             [Ann.BitCode, ['{:d}'.format(bit)]])
                    self.data.insert(0, bit)
                else:
                    self.reset()
                self.samplenum_save = self.samplenum

                # Code complete
                if len(self.data) == 12:

                    code = bitpack(self.data)

                    f = '0x{{:0{}X}}'.format(3)
                    self.put(self.samplenum_field, self.samplenum, self.anchor,
                             [Ann.Code, [f.format(code)]])

                    self.hex = code
                    self.samplenum_field = self.samplenum
                    self.state = 'Stop'

            # Stop
            elif self.state == 'Stop':
                self.put(self.samplenum_field, self.samplenum_save + self.stop,
                         self.anchor, [Ann.BitStop, ['Stop', 'S']])
                self.put(self.samplenum_field, self.samplenum_save + self.stop,
                         self.anchor, [Ann.Footer, ['Stop', 'S']])

                oricode = ori.get(self.hex, 'Unknown RI code')
                self.put(self.samplenum_decode,
                         self.samplenum_save + self.stop, self.anchor,
                         [Ann.Decode, [
                             '{}'.format(oricode),
                         ]])

                self.samplenum_save = self.samplenum_field = self.samplenum
                self.state = 'Idle'