Esempio n. 1
0
class MachineMeter(object):
    def __init__(self):        
        """Serial and other"""
        self.model = ""
        self.device_connected = False
        self.ser = None

        self.s_t = Serial_Tools(self.ser) # Tool to help issuing without waiting.
        self.s_t.show_messages = False
        
        scom = Scope_Commander(self.ser)

        """TRACE AND DUMP SETTINGS"""
        self.trace_size = 512 # Captured trace size in samples.
        self.extra_trace = 16 # ADC warmup junk
        self.whole_trace = self.trace_size + self.extra_trace
        self.d_dec = 16
        self.d_size = (self.trace_size / self.d_dec) * 2 # Dump size in bytes
        self.ex_size = (self.extra_trace / self.d_dec) * 2 # Extra samples for ADC warmup in bytes
        self.whole_dump = ((self.trace_size + self.extra_trace) / self.d_dec) * 2
        self.div = float(self.d_size)
        
        """ STATE. IT'S HERE """
        self.state = self.s_find_device

        self.data = {}
        self.data['ranges'] = {
            "BS0005":(-5.28, 8.11), # <1% error
            "BS0010":(-4.84, 10.8) # Not sure on this one!
        }

        """ Measurement data """
        self.data['ch'] = {}
        self.data['ch']['a'] = {
            'raw_avg':  0,
            'clip':     {'top':False, 'bot':False},
            'ana':      0.0,
            'display':  0.0,
            'ready':    {'data':False, 'display':False},
            'ena':      False,
            'was_ena':  False,
            'text_out': ""
        }

        """ Mult """
        self.data['mult'] = {'values':[1,2,5,10]}
        self.data['ch']['a']['mult_index'] = 0

        """ Logic """
        self.data['logic'] = {
            'step':     0.100,
            'rounding': 3,
            'min':      -6.000,
            'max':      6.000
        }
        self.data['ch']['a']['logic'] = {'top':1.5,'bot':0.0,'ena':False,'val':0}
        
        """ OTHER """
        self.data['ch']['a']['zero'] = 0.00

        self.data['diff'] = {
            'ena': False,
            'zero':0.00,
            'display':0.00,
            'text_out':""
        }

        self.data['frame_toggle'] = 0

        """ Interpolation for Enhanced """
        self.data['enhanced'] = {
            'ena': False,
            'frame': {'count': 0, 'max': 24}
        }
        self.data['ch']['a']['interp'] = {
            'queue': [0,0,0,0,0,0,0,0,0],
            'value': 0.0
        }

        self.data['device'] = {
            'model':None,
            'connected':False
        }
        
        self.data['mode'] = {
            'single':True,
            'dual':False,
            'diff':False,
            'logic':False
        }

        self.data['ch']['b'] = {}
        copy_dict(self.data['ch']['a'], self.data['ch']['b'])
        self.ch = self.data['ch']
        self.a = self.data['ch']['a']
        self.b = self.data['ch']['b']
        self.diff = self.data['diff']
        
        # Start the engine.... In the key of a.
        self.force_ch('a', True)
        
        self.range_in_use = self.data['ranges']['BS0005']
        

    """ API Functions """
    def step_limit(self, ch, top_bot, inc):
        if self.ch[ch]['logic']['ena']:
            lim = self.ch[ch]['logic']
            lim[top_bot] = round(lim[top_bot] + inc, 1)
            if lim[top_bot] < self.data["logic"]['min']:
                lim[top_bot] = self.data["logic"]['min']
            elif lim[top_bot] > self.data["logic"]['max']:
                lim[top_bot] = self.data["logic"]['max']

    def toggle_limits(self, ch):
        self.ch[ch]['logic']['ena'] = not self.ch[ch]['logic']['ena']

    def step_mult(self, ch, inc):
        if self.ch[ch]['ena']:
            ch = self.ch[ch]
            ch['mult_index'] += inc
            if ch['mult_index'] < 0:
                ch['mult_index'] = 0
            elif ch['mult_index'] >= len(self.data['mult']['values']):
                ch['mult_index'] = len(self.data['mult']['values']) - 1

    def toggle_ch(self, ch):
        self.ch[ch]['ena'] = not self.ch[ch]['ena']

    def force_ch(self, ch, state):
        self.ch[ch]['ena'] = state

    def zero_ch(self, ch):
        if self.ch[ch]['ena']:
            if self.data['diff']['ena'] and ch == 'a':
                self.data['diff']['zero'] = self.ch[ch]['display'] + self.data['diff']['zero']
            else:
                self.ch[ch]['zero'] = self.ch[ch]['display'] + self.ch[ch]['zero']

    def toggle_diff(self):
        self.data['diff']['ena'] = not self.data['diff']['ena']

    def force_diff(self, state):
        self.data['diff']['ena'] = state

    def toggle_sound(self):
        self.sound_enabled = not self.sound_enabled

    def toggle_enhanced(self):
        self.data['enhanced']['ena'] = not self.data['enhanced']['ena']

    def force_enhanced(self, state):
        self.data['enhanced']['ena'] = state

    """ STATES """

    def s_find_device(self):
        self.ser = self.s_t.find_device()
        if self.ser != None:
            self.data['device']['connected'] = True
            self.state = self.s_check_model
        else:
            if self.device_connected:
                self.data['device']['connected'] = False
            self.state = self.s_find_device

    def s_check_model(self):
        self.ser.flushInput() #Try to get anything in the buffer.
        self.s_t.clear_waiting() #Force the counter to reset.
        self.s_t.issue_wait("?")
        self.data['device']['model'] = (self.ser.read(20)[1:7])
        print self.data['device']['model'] + " Connected."

        self.dirty = True
        if self.data['device']['model'] in self.data['ranges']:
            self.state = self.s_setup_bs
        else:
            self.state = self.s_check_model

    def s_setup_bs(self):
        """ Put the BS into a workable state """
        si = self.s_t.issue
        siw = self.s_t.issue_wait
        self.range_in_use = self.data['ranges'][self.data['device']['model']]
        siw("!")
        si(
            "[1c]@[%s]sn[%s]s" % l_endian_hexify(self.whole_dump / 2) # Dump size
            + "[1e]@[06]s[21]@[12]s" # Dump, trace mode = filter, macro
            + "[08]@[00]sn[00]sn[00]s" # Spock address
            + "[16]@[01]sn[00]s" # Iterations = 1
            + "[26]@[%s]sn[%s]s" % l_endian_hexify(16) # Pre trig cap
            + "[2a]@[%s]sn[%s]s" % l_endian_hexify(self.whole_trace) # Post trig cap
            + "[30]@[00]s" # Dump channel
            + "[31]@[04]s" # Buffer mode = macro
            + "[37]@[01]s" # Analogue channel enable
            + "[2c]@[00]sn[0a]s" # Time out (REALLY IMPORTANT)
            + "[2e]@[90]sn[01]s" # Clock ticks
            + "[14]@[01]sn[00]s" # Clock scale
            ### Filter mode ###
            + "[18]@[10]sn[00]s" # Dump send = 16
            + "[1a]@[00]sn[00]s" # Skip = 0
            ### Range ###
            + "[66]@[ff]sn[ff]s" # High
            + "[64]@[00]sn[00]s" # Low
        )
        self.ser.flushInput()

        siw("U")
        siw(">")
        
        self.state = self.s_change_to_chop

    def s_change_to_chop(self):
        self.ser.flushInput()
        self.s_t.clear_waiting()
        self.s_t.issue(
            "[1e]@[06]s" # Set dump mode stays as filter
            "[21]@[13]s" # Set trace mode (macro chop)
            "[31]@[05]s" # Buffer mode
            "[37]@[03]s" # Ana ch enable
        )
        self.s_t.issue_wait(">")
        self.s_t.issue("U")

        self.state = self.s_pre_idle

    def s_pre_idle(self):
        self.s_t.clear_waiting()
        self.ser.flushInput()
        self.state = self.s_idle

    def s_idle(self): # Idle
        self.s_t.issue_wait("?")
        self.ser.flushInput()
        if self.a['ena'] or self.b['ena']:
            self.state = self.s_init_a_b_req_chop

    """ Dual chop """
    def s_init_a_b_req_chop(self):
        self.s_t.clear_waiting()
        self.ser.flushInput()
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[03]sD")
        self.state = self.s_a_dump_chop

    def s_a_dump_chop(self):
        self.s_t.clear_waiting()
        self.ser.read(33) # Get rid of unused timing junk
        self.s_t.issue_wait(">")
        self.s_t.issue("[30]@[00]sA") # Dump chA

        if self.a['ena'] or self.b['ena']:
            self.state = self.s_a_proc_b_dump_chop
        else:
            self.state = self.s_pre_idle

    def s_a_proc_b_dump_chop(self):
        self.s_t.clear_waiting()
        if self.ch['a']['ena']:
            self.ser.read(self.ex_size)
            dump = convert_12bit_bin_dump(self.ser.read(self.d_size))
            self.a['ana'] = self.derive_voltage(dump)
            self.a['clip']['top'], self.a['clip']['bot'] = self.check_clipping(dump)
            self.a['ready']['data'] = True
        else:
            self.ser.read(self.d_size + self.ex_size) # Read off dump as junk.
            self.b['ready']['data'] = False
        self.s_t.issue_wait(">")
        self.s_t.issue("[30]@[01]sA") # Dump chB

        self.state = self.s_b_proc_a_b_req_chop

    def s_b_proc_a_b_req_chop(self):
        self.s_t.clear_waiting()
        if self.b['ena']:
            self.ser.read(self.ex_size)
            dump = convert_12bit_bin_dump(self.ser.read(self.d_size))
            self.b['ana'] = self.derive_voltage(dump)
            self.b['clip']['top'], self.b['clip']['bot'] = self.check_clipping(dump)
            self.b['ready']['data'] = True
        else:
            self.ser.read(self.d_size + self.ex_size) # Read off dump as junk.
        self.a['ready']['data'] = False
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[03]sD") # Request both channels.

        self.state = self.s_a_dump_chop

    """ Utility functions """
    def volt_interp(self, ls, new_v):
        ls.pop(0)
        ls.append(new_v)
        return round((sum(ls) / len(ls)), 4)
        
    def derive_voltage(self, dump):
        avg = sum(dump) / len(dump)
        # Map 16 bit range to voltage range
        return to_range(avg, (-32768, 32767), self.range_in_use)
        
    def check_clipping(self, dump):
        clip_top, clip_bot = False, False
        if (max(dump) > (32767 - 72)): # Clipping top WHY 72?!?!?!
            clip_top = True
            
        if (min(dump) < (-32768 + 32)): # Clipping bottom
            clip_bot = True
            
        return (clip_top, clip_bot)

    def update(self):
        """ Do state! """
        try:
            self.state()
        except serial.SerialException:
            print "Device disconected | Error: SE"
            self.state = self.s_find_device
        except serial.SerialTimeoutException:
            print "Device disconected | Error: STE"
            self.state = self.s_find_device

        a = self.a
        b = self.b
        a_ready = a['ready']
        b_ready = b['ready']
        a_interp = a['interp']
        b_interp = b['interp']
        diff = self.diff
        enhanced_frame = self.data['enhanced']['frame']
        
        """ Data post-process """
        if self.data['device']['connected']:
            for ch, ch_ready in (a, a_ready), (b, b_ready):
                if ch['ena'] and ch_ready['data']:
                    ch['ana'] = round((ch['ana'] - ch['zero']), 6) # Zero
                    ch['display'] = ch['ana'] * self.data['mult']['values'][ch['mult_index']] # Apply multiplier
                    if ch['logic']['ena']:
                        if ch['display'] >= ch['logic']['top']:
                            log = 1
                        elif ch['display'] <= ch['logic']['bot']:
                            log = 2
                        else:
                            log = 0
                    else:
                        log = 0
                    ch['logic']['val'] = log
                
            """ INTERP MODE """
            if self.data['enhanced']['ena']:
                for ch, ch_interp in (a, a_interp), (b, b_interp):
                    if ch['ena'] and ch['ready']['data']:
                        ch_interp['value'] = self.volt_interp(ch_interp['queue'], ch['display'])
                        ch['display'] = ch_interp['value']

            """ DIFF MODE """
            if diff['ena']:
                a['display'] = (a['ana'] - b['ana']) - diff['zero']

            """ SLOW DOWN INTERP """
            if self.data['enhanced']['ena']:
                for ch, count in (a, 0), (b, 12):
                    if ch['ena'] and enhanced_frame['count'] == count:
                        ch['ready']['display'] = True
                
                enhanced_frame['count'] += 1
                if enhanced_frame['count'] >= enhanced_frame['max']-1:
                    enhanced_frame['count'] = 0

            else:
                a_ready['display'] = True
                b_ready['display'] = True

            if self.data['enhanced']['ena']: # Check interp, set rounding
                round_to = "4"
            else:
                round_to = "3"
                
            """ Set the text """ # This should really be done by the widget
            reduce_to = "%." + round_to + "f" # Max length of voltage is 8 chars
            for ch, ch_ready in (a, a_ready), (b, b_ready):
                if ch['ena'] and ch_ready['display']:
                    ch['text_out'] = (reduce_to % ch['display'] + "v").rjust(8)
                    ch_ready['display'] = False
Esempio n. 2
0
class MachineTriggeredLogic(object):
    def __init__(self):
        """Serial Setup"""
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False

        self.state = self.s_find_device
        
        self.buffer_size = 12288
        
        self.trace_size = 12000
        self.trace_received = 0
        
        self.trace_intro = 16
        self.trace_outro = self.trace_size
        
        self.command = ""

        """Data exposed through API"""
        self.data = {
            "device":{"connected":False, "model":None},
            "accepted_models":["BS0005", "BS0010"],
            "status":"stopped",
            "ba":bytearray(),
            "ba_pos":0,
            "ba_range":1000,
            "ba_zoom":(0,1000),
            "range_high":20000,
            "range_low":100,
            "deep_scan":False,
            "data_ready":False,
            "trigger_byte":0,
            "mask_byte":255, # Any bit marked as ? will be a "don't care" bit
            "trigger":[2,2,2,2,2,2,2,2],
            "rate":5000, # kHz (up to 5mHz on tmLogic)
            "running":False
        }

    """API Functions"""
    def inc_trigger(self, ch, inc):
        trig = self.data["trigger"]
        trig[ch] += inc
        if trig[ch] == 3:
            trig[ch] = 0
        
        self.data["trigger_byte"] = self.to_trigger_byte(trig)
        self.data["mask_byte"] = self.to_mask_byte(trig)
        tb = l_endian_hexify(self.data["trigger_byte"], 1)
        mb = l_endian_hexify(self.data["mask_byte"], 1)
        self.command += "[05]@[%s]s[06]@[%s]s" % (tb[0], mb[0]) # Trigger logic and mask
        
    def stop_start(self):
        if self.data['running']:
            self.data['running'] = False
            self.state = self.s_idle
            self.s_t.issue_wait(".")
        elif not self.data['running']:
            self.data['running'] = True
            self.state = self.s_start_capture
            
    def set_ba_pos(self, val):
        zr = self.data['ba_zoom']
        pos = to_range(val, [0,100], zr)
        pos = self.check_position(pos - self.data['ba_range'] / 2)
        self.data['ba_pos'] = int(pos)
        
    def inc_ba_range(self, inc):
        # Make some data local and get centre
        sd = self.data
        bar = sd['ba_range']
        bap = sd['ba_pos']
        old_centre = bap + (bar / 2)
        # Increment
        sd['ba_range'] = int(inc_125_pattern(bar, inc))
        # Get new, unaltered centre, and adjust the view pos
        new_centre = bap + (sd['ba_range'] / 2)
        sd['ba_pos'] -= int(new_centre - old_centre)
        # Refresh locals
        bar = sd['ba_range']
        bap = sd['ba_pos']
        # Check
        if ((bar + bap) > len(sd['ba']) or
            bar > sd['range_high'] or
            bar < sd['range_low'] or
            bap < 0):
            # Reverse
            self.inc_ba_range(-inc)
            
    """ Utilities """
    def to_trigger_byte(self, bit_ls):
        to_bit = lambda x : str(int(x > 0))
        bit_str = "".join(map(to_bit, bit_ls))
        return int(bit_str, 2)
                        
    def to_mask_byte(self, bit_ls):
        to_mask = lambda x : str(int(x == 2))
        bit_str = "".join(map(to_mask, bit_ls))
        return int(bit_str, 2)
        
    def check_position(self, pos):
        ba_range = self.data['ba_range']
        ba_len = len(self.data['ba'])
        if (pos + ba_range) > ba_len:
            return int(ba_len - ba_range)
        elif pos < 0:
            return 0
        else:
            return int(pos)
        
    """States"""
    def s_find_device(self):
        self.ser = self.s_t.find_device()
        if self.ser != None:
            self.data['device']['connected'] = True
            self.state = self.s_check_model
        else:
            if self.data['device']['connected']:
                self.data['device']['connected'] = False
            self.state = self.s_find_device

    def s_check_model(self):
        self.ser.flushInput() #Try to get anything in the buffer.
        self.s_t.clear_waiting() #Force the counter to reset.
        self.s_t.issue_wait("?")
        model = (self.ser.read(20)[1:7])
        self.data['device']['model'] = model
        self.dirty = True
        if model in self.data['accepted_models']:
            self.state = self.s_setup_bs
            print self.data['device']['model'] + " Connected."
        else:
            self.state = self.s_check_model

    def s_setup_bs(self):
        si = self.s_t.issue
        siw = self.s_t.issue_wait
        self.command = ""
        siw("!")
        si(
            "[21]@[0e]s" # Logic trace mode
            + "[1e]@[00]s" # Dump mode
            + "[1c]@[%s]sn[%s]s" % l_endian_hexify(self.trace_size) # Dump
            + "[31]@[00]s" # Buffer mode
            + "[14]@[01]sn[00]s" # Clock scale
            + "[2a]@[%s]sn[%s]s" % l_endian_hexify(self.trace_size) # Post trig cap
            + "[30]@[80]s" # Dump channel
            + "[37]@[00]s" # Analogue chan
            + "[38]@[00]s" # Digital
            + "[18]@[00]sn[00]s" # Dump send
            + "[1a]@[00]sn[00]s" # Dump skip
        )
        ticks = int(freq_to_ns(self.data["rate"]) / 25)
        si("[2e]@[%s]sn[%s]s" % l_endian_hexify(ticks))
        # Trigger
        si(
            "[2c]@[00]sn[00]s" # Trigger timeout (NEVER!)
            "[07]@[01]s" # Trigger mode (spock opt) (hardware/rising edge)
            "[32]@[01]sn[00]sn[01]sn[00]s" # Trigger intro and outro
        )
        tb = hex(self.data["trigger_byte"])[2:]
        mb = hex(self.data["mask_byte"])[2:]
        si("[05]@[%s]s[06]@[%s]s" % (tb, mb))
        siw(">")
        siw("U")
        
        self.state = self.s_idle
    
    def s_idle(self):
        self.s_t.issue_wait("?")
        self.ser.flushInput()
        if self.command and self.ser:
            self.s_t.issue_wait(self.command)
            self.command = ""
        
    def s_start_capture(self):
        self.data['data_ready'] = False
        self.data['ba'] = bytearray()
        self.trace_received = 0
        self.s_t.clear_waiting()
        self.ser.flushInput()
        if self.command and self.ser:
            self.s_t.issue_wait(self.command)
            self.command = ""
        self.s_t.issue_wait(">")
        self.s_t.issue("D")
        self.state = self.s_await_trigger
    
    def s_await_trigger(self):
        self.s_t.clear_waiting()
        returned = self.ser.inWaiting()
        if returned >= 12:
            self.ser.read(12) # Read out the first part of the timing info
            self.state = self.s_await_complete
        else:
            self.state = self.s_await_trigger
    
    def s_await_complete(self):
        returned = self.ser.inWaiting()
        if returned >= 21: # Trace has finished!
            self.ser.read(12) # Pesky other information
            end_address = unhexify(self.ser.read(8))
            self.ser.read(1) # Last byte
            # Set up spock stuff
            start_address = ((end_address + self.buffer_size) - self.trace_size) % self.buffer_size
            self.s_t.issue("[08]@[%s]sn[%s]sn[%s]s" % l_endian_hexify(start_address, 3))
            self.s_t.issue_wait(">")
            # Dump!
            self.s_t.issue("A")
            self.state = self.s_acquire
        else:
            self.state = self.s_await_complete
        
    def s_acquire(self):
        self.s_t.clear_waiting() # Bye 'A'
        to_get = self.ser.inWaiting()
        self.trace_received += to_get
        self.data['ba'] += self.ser.read(to_get)
        if self.trace_received == self.trace_size:
            self.data['data_ready'] = True
            self.data['running'] = False
            self.data['ba_range'] = self.trace_size
            self.state = self.s_idle

    """Data Processing Functions"""

    """Update Functions"""

    def update(self):
        try:
            self.state()
        except serial.SerialException:
            print "Device disconnected | Error: SE"
            self.state = self.s_find_device
        except serial.SerialTimeoutException:
            print "Device disconnected | Error: STE"
            self.state = self.s_find_device
Esempio n. 3
0
class MachineScope(object):
    def __init__(self):
        """Serial Setup"""
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False

        self.state = self.s_find_device
        
        self.trace_size = 1024 # Samples
        self.extra_trace = 4
        self.whole_trace = self.trace_size + self.extra_trace
        self.dump_size = self.trace_size
        self.extra_dump = self.extra_trace
        self.whole_dump = self.dump_size + self.extra_dump
        
        self.write_buffer = ""
        
        self.buffer_size = 3 * 4096

        """Data exposed through API"""
        self.data = {
            "device":{"connected":False, "model":None},
            "accepted_models":["BS0005", "BS0010"],
            "ch":{"active":{}},
            "trigger_level":32000,
            "trigger_display":0,
            "range_data":{"top":32000, "bot":0},
            "range":{"min":-5.8, "max":5.8, "high":4.0, "low":-1.0, "offset":1.5, "span":5.0},
            "timebase":{"min":15, "max":535, "value":40, "display":""},
            "current_channel":"a",
            "waveform":0,
            "symetry":32768,
            "symetry_percentage":50,
            "frequency":4,
            "on_time":0,
            "off_time":0
        }
                
        self.data['ch']['active'] = {
            "trace":[],
            "display_trace":[]
        }
        
        self.data['spock_option'] = [0,0,0,0,0,0,0,0] # This is BEian (7 -> 0)
        
        self.active = self.data['ch']['active']
        self.device = self.data['device']
        self.compute_times()
        self.ticks_to_timebase()

    """ Helper Functions """
    
    def compute_times(self):
        """ Works out the on and off times, based on the
            frequency and symetry.
        """
        d = self.data
        freq = d['frequency'] * 1000
        p_length = freq ** -1
        d['on_time'] = (p_length) * (d['symetry_percentage'] / 100.0)
        d['off_time'] = (p_length) * ((100.0 - d['symetry_percentage']) / 100.0)
        d['on_time'] = d['on_time'] * 1000000
        d['off_time'] = d['off_time'] * 1000000
        
    def restart_awg(self):
        """ Resends all AWG commands that can be altered in this mode """
        d = self.data
        leh = l_endian_hexify
        ### Synthesise ###
        out = (
        "[46]@[00]s" # CV
        + "[47]@[" + str(d['waveform']) + "]s"
        + "[5a]@[%s]sn[%s]s" % leh(d['symetry'], 2) # Phase Ratio
        + "Y"
        ### Translate ###
        + "[47]@[00]s"
        + "[5a]@[26]sn[31]sn[08]sn[00]s" # Phase Ratio
        + "X"
        ### Generate ###
        + "[46]@[02]s"
        + "[50]@[%s]sn[%s]s" % leh(self.freq_to_ticks(), 2) # Clock ticks 
        + "Z"
        )
        
        self.write_buffer += out
        
    def freq_to_ticks(self):
        """ Frequency relies on a constant phase ratio at the translate
            command.
            With 0x00083126 we get 8 periods per 1000 point table.
            clock_ticks = period / points_per_period
            frequency is in Hz, clock_ticks are 25ns long.
        """
        d = self.data
        points_per_period = 125.0
        period = (d['frequency'] * 1000.0) ** -1
        ticks_per_period = period / 0.000000025
        return int(round(ticks_per_period / points_per_period))
        
    def ticks_to_timebase(self):
        tb = self.data['timebase']
        tb['display'] = self.trace_size * (tb['value'] * 25)
        tb['display'] *= 0.000001
        
    """ API Functions """
        
    def step_waveform(self, inc):
        d = self.data
        d['waveform'], changed = increment(d['waveform'], inc, 0, 3)
        if changed:
            self.restart_awg()
        
    def reset_symetry(self):
        sym = 50
        self.data['symetry_percentage'] = sym
        self.data['symetry'] = int(to_range(sym, (0, 100),(0, 65535)))
        self.compute_times()
        self.restart_awg()
        
    def reset_frequency(self):
        self.data['frequency'] = 4
        self.compute_times()
        self.restart_awg()
        
    def snap_symetry(self):
        d = self.data
        sym = round_to_n(d['symetry_percentage'], 2)
        d['symetry_percentage'] = sym
        d['symetry'] = int(to_range(sym, (0, 100),(0, 65535)))
        self.compute_times()
        self.restart_awg()
        
    def snap_frequency(self):
        d = self.data
        d['frequency'] = round_to_n(d['frequency'], 2)
        self.compute_times()
        self.restart_awg()
        
    def snap_on_off_time(self, select):
        d = self.data
        on = d['on_time']
        off = d['off_time']
        if select == "on":
            on = round_to_n(on, 2)
        elif select == "off":
            off = round_to_n(off, 2)
            
        on_frac = on / 1000000.0
        off_frac = off / 1000000.0
        
        newFreq = (((on_frac + off_frac) ** -1) / 1000.0)
        newSym = to_range(on_frac, (0, on_frac + off_frac), (0, 100))
        if 0.06 <= newFreq <= 8.0 and 0.0 <= newSym <= 100.0:
            d['on_time'] = on
            d['off_time'] = off
            d['frequency'] = newFreq
            d['symetry_percentage'] = newSym
            d['symetry'] = int(to_range(newSym, (0,100), (0,65535)))
            self.restart_awg()
        
    def adjust_symetry(self, inc):
        d = self.data
        d['symetry_percentage'], changed = increment(d['symetry_percentage'], inc, 0, 100)
        if changed:
            d['symetry'] = int(to_range(d['symetry_percentage'], (0,100), (0,65535)))
            self.restart_awg()
            self.compute_times()
        
    def adjust_frequency(self, inc):
        d = self.data
        d['frequency'], changed = increment(d['frequency'], inc, 0.6, 8.0)
        if changed:
            self.restart_awg()
            self.compute_times()
            
    def adjust_on_off_time(self, select, inc):
        d = self.data
        on_inc, off_inc = 0, 0
        if select == "on":
            on_inc = inc
        elif select == "off":
            off_inc = inc
        on = (d['on_time'] + on_inc) / 1000000.0
        off = (d['off_time'] + off_inc) / 1000000.0
        newFreq = (((on + off) ** -1) / 1000.0)
        newSym = to_range(on, (0, on + off), (0, 100))
        if 0.06 <= newFreq <= 8.0 and 0.0 <= newSym <= 100.0:
            d['on_time'] = on * 1000000
            d['off_time'] = off * 1000000
            d['frequency'] = newFreq
            d['symetry_percentage'] = newSym
            d['symetry'] = int(to_range(newSym, (0,100), (0,65535)))
            self.restart_awg()
    
    def adjust_timebase(self, inc):
        tb = self.data['timebase']
        tb['value'], changed = increment(tb['value'], inc, tb['min'], tb['max'])
        if changed:
            self.write_buffer += ("[2e]@[%s]sn[%s]s" % l_endian_hexify(tb['value']))
            self.ticks_to_timebase()
        
    def change_channel(self):
        """ Changes the capture channel, and the trigger channel """
        if self.data['current_channel'] == "a":
            self.data['current_channel'] = "b"
            code = "2"
            self.data['spock_option'][5] = True # Source bit (true = b, false = a)
        else:
            self.data['current_channel'] = "a"
            code = "1"
            self.data['spock_option'][5] = False
        self.write_buffer += "[37]@[0" + code + "]s"
        s_op = from_bin_array(self.data['spock_option'])
        self.write_buffer += "[07]@[%s]s" % l_endian_hexify(s_op,1)
            
    def move_range(self, inc):
        r = self.data['range']
        if (r['high'] + inc) <= r['max'] and (r['low'] + inc) >= r['min']:
            self.adjust_range('high', inc)
            self.adjust_range('low', inc)
                        
    def adjust_range(self, hl, inc):
        r = self.data['range']
        r[hl] += inc
        if (r[hl] > r['max'] or r[hl] < r['min']
            or r['low'] >= r['high']):
            r[hl] -= inc
        else:
            r[hl] = round(r[hl], 1)
            # Get scale
            scale = r['high'] - r['low']
            r['span'] = scale
            # Get offset
            r['offset'] = r['low'] + (scale / 2)
            # Compute register values
            high, low = to_span(r['offset'], scale, self.data['device']['model'])
            # Figure out trigger
            trig_voltage = r['low'] + ((r['high'] - r['low']) / 2)
            self.data['trigger_display'] = trig_voltage
            self.data['trigger_level'] = int(to_range(trig_voltage, [-7.517, 10.816], [0,65535]))
            # Submit high, then low
            self.write_buffer += "[68]@[%s]sn[%s]s" % l_endian_hexify(self.data['trigger_level'], 2)
            self.write_buffer += "[66]@[%s]sn[%s]s" % l_endian_hexify(high)
            self.write_buffer += "[64]@[%s]sn[%s]s" % l_endian_hexify(low)
            
    def adjust_span(self, inc):
        r = self.data['range']
        if (r['high'] + inc) <= r['max'] and (r['low'] - inc) >= r['min']:
            self.adjust_range('high', inc)
            self.adjust_range('low', -inc)

    """ Utility States """
    def s_find_device(self):
        self.ser = self.s_t.find_device()
        if self.ser != None:
            self.data['device']['connected'] = True
            self.state = self.s_check_model
            
        else:
            if self.data['device']['connected']:
                self.data['device']['connected'] = False
            self.state = self.s_find_device

    def s_check_model(self):
        self.ser.read(10000) # Try to get anything in the buffer.
        self.s_t.clear_waiting() # Force the counter to reset.
        self.s_t.issue_wait("?")
        model = (self.ser.read(20)[1:7])
        self.data['device']['model'] = model

        self.dirty = True
        if model in self.data['accepted_models']:
            self.state = self.s_setup_bs
            print self.data['device']['model'] + " Connected."
        else:
            self.state = self.s_check_model
    
    """ States """
    def s_setup_bs(self):
        siw = self.s_t.issue_wait
        si = self.s_t.issue
        leh = l_endian_hexify
        d = self.data
        ### General ###
        siw("!") # Reset!
        si(
            "[1c]@[%s]sn[%s]s" % leh(self.whole_dump) # Dump size
            + "[1e]@[00]s" # Dump mode
            + "[21]@[00]s" # Trace mode
            + "[08]@[00]sn[00]sn[00]s" # Default spock address
            + "[16]@[01]sn[00]s" # Iterations to 1
            + "[2a]@[%s]sn[%s]s" % leh(self.whole_trace) # Post trig cap
            + "[30]@[00]s" # Dump channel
            + "[31]@[00]s" # Buffer mode
            + "[37]@[01]s" # Analogue chan enable
            + "[26]@[01]sn[00]s" # Pre trig capture
            + "[22]@[00]sn[00]sn[00]sn[00]s" # Trigger checking delay period.
            + "[2c]@[00]sn[0a]s" # Timeout
            + "[2e]@[%s]sn[%s]s" % leh(d['timebase']['value']) # Set clock ticks
            + "[14]@[01]sn[00]s" # Clock scale

            ### Trigger ###
            + "[06]@[7f]s" # TriggerMask
            + "[05]@[80]s" # TriggerLogic
            + "[32]@[04]sn[00]s" # TriggerIntro
            + "[34]@[04]sn[00]s" # TriggerOutro
            + "[44]@[00]sn[00]s" # TriggerValue
            + "[68]@[%s]sn[%s]s" % leh(d['trigger_level'], 2) # TriggerLevel
            + "[07]@[%s]s" % leh(from_bin_array(d['spock_option']), 1) # SpockOption
        )
        ### Range / Span ###
        high, low = to_span(d['range']['offset'], d['range']['span'], d['device']['model'])
        si(
        "[66]@[%s]sn[%s]s" % l_endian_hexify(high)
        + "[64]@[%s]sn[%s]s" % l_endian_hexify(low)
        )
        
        ### AWG ###
        siw(
            "[7c]@[c0]s[86]@[00]s" # AWG on, clock gen off
            # Synthesize
            + "[46]@[00]sn[" + str(d['waveform']) + "]s" # CV, Op Mode
            + "[5a]@[%s]sn[%s]s" % leh(d['symetry'], 2) # Phase Ratio
            + "Y"
        )
        siw(
            # Translate
            "[47]@[00]s" # CV, Op Mode
            + "[4a]@[e8]sn[03]sn[00]sn[00]sn[00]sn[00]s" # Size, Index, Address
            + "[54]@[ff]sn[ff]sn[00]sn[00]s" # Level, Offset
            + "[5a]@[26]sn[31]sn[08]sn[00]s" # Phase Ratio
            + "X"
        )
        siw(
            # Generate
            "[48]@[f4]sn[80]s[52]@[e8]sn[03]s" # Option, Modulo
            + "[50]@[%s]sn[%s]s" % leh(self.freq_to_ticks()) # Clock ticks
            + "[5e]@[0a]sn[01]sn[01]sn[00]s" # Mark, Space
            + "[78]@[00]sn[7f]s" # Dac Output
            + "[46]@[02]s"
            + "Z"
        )
        
        ### Update ###
        self.s_t.issue_wait(">")
        siw("U")
        self.s_t.clear_waiting()
        self.ser.flushInput()
        
        self.state = self.s_init_req
        
    def s_init_req(self):
        self.s_t.clear_waiting()
        self.ser.flushInput()
        self.s_t.issue_wait(">")
        self.s_t.issue("D")
        
        self.state = self.s_dump
        
    def s_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(24)
        end_address = unhexify(self.ser.read(8))
        self.ser.read(1)
        start_address = ((end_address + self.buffer_size) - self.whole_trace) % self.buffer_size
        self.s_t.issue("[08]@[%s]sn[%s]sn[%s]s" % l_endian_hexify(start_address, 3))
        self.s_t.issue_wait(">")
        self.s_t.issue("A")
        
        self.state = self.s_proc_req
        
    def s_proc_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.extra_dump)
        self.active['trace'] = convert_8bit_dump(self.ser.read(self.dump_size))
        if self.write_buffer:
            self.s_t.issue(self.write_buffer)
            self.s_t.issue_wait("U")
            self.write_buffer = ""
        
        self.s_t.issue_wait(">")
        self.s_t.issue("D")
        
        self.state = self.s_dump
        
    """Data Processing Functions"""

    """Update Functions"""

    def update(self):
        try:
            self.state()
        except serial.SerialException:
            print "Device disconected | Error: SE"
            self.state = self.s_find_device
        except serial.SerialTimeoutException:
            print "Device disconected | Error: STE"
            self.state = self.s_find_device
Esempio n. 4
0
class MachineSound(object):
    def __init__(self):
        """Serial Setup"""
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False

        self.state = self.s_find_device
        self.base_freq = 440  # A
        self.note = 0
        """Data exposed through API"""
        self.data = {
            "device": {
                "connected": False,
                "model": None
            },
            "accepted_models": ["BS0005", "BS0010"]
        }

    """ Utilities """

    def generate_frequency(self, note_id):
        # fn = f0 * (a)n
        # a = 1.05946309
        return self.base_freq * (1.05946309**note_id)

    def inc_note(self, inc):
        notes = [
            "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"
        ]
        self.note += inc
        # The ocatave number
        print "Note ID", self.note
        print "Note", notes[self.note % 12], int(self.note / 12) + 4
        print "Freq", self.generate_frequency(self.note)

    """API Functions"""

    def change_wf(self, val):
        if self.ser:
            self.s_t.issue_wait("[50]@[%s]sn[%s]s" % l_endian_hexify(val))
            self.s_t.issue_wait("Z")

    def change_wf2(self, val=0):
        freq = int(to_range(val, [0, 100], [100, 260]))
        if self.ser:
            self.s_t.issue_wait("[50]@[%s]sn[%s]s" % l_endian_hexify(freq))
            self.s_t.issue_wait("Z")

    """States"""

    def s_find_device(self):
        self.ser = self.s_t.find_device(self.data['accepted_models'])
        if self.ser != None:
            self.data['device']['connected'] = True
            self.state = self.s_check_model
        else:
            if self.data['device']['connected']:
                self.data['device']['connected'] = False
            self.state = self.s_find_device

    def s_check_model(self):
        self.ser.read(10000)  # Try to get anything in the buffer.
        self.s_t.clear_waiting()  # Force the counter to reset.
        self.s_t.issue_wait("?")
        model = (self.ser.read(20)[1:7])
        self.data['device']['model'] = model
        print self.data['device']['model'] + " Connected."

        self.dirty = True
        if model in self.data['accepted_models']:
            self.state = self.s_setup_bs
        else:
            self.state = self.s_check_model

    def s_setup_bs(self):
        """AWG"""
        self.s_t.issue_wait(
            "[7c]@[c0]s"  # Kitchen sink register B! ENABLES AWG!!!
            "[86]@[00]s"  # Turn the clock generator off.
        )
        self.s_t.issue_wait("U")
        self.s_t.issue_wait(
            "[46]@[00]s"  # vpCmd (Command Vector)
            "[47]@[03]s"  # vpMode (Operating Mode)
            "[5a]@[00]sn[80]sn[00]sn[00]s"  # vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("Y")  # SYNTHESIZE!
        self.s_t.issue_wait(
            "[46]@[00]s"  # vpCmd (Command Vector)
            "[47]@[00]s"  # vpMode (Operating Mode)
            "[4a]@[e8]sn[03]s"  # vpSize (Operation size, 1000 samples)
            "[4c]@[00]sn[00]s"  # vpIndex (Operation Index, table start)
            "[4e]@[00]sn[00]s"  # vpAddress (Destination Address, buffer start)
            "[54]@[ff]sn[ff]s"  # vpLevel (Output Level, full scale)
            "[56]@[00]sn[00]s"  # vpOffset (Output Offset, zero)
            "[5a]@[93]sn[18]sn[04]sn[00]s"  # vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("X")  # TRANSLATE!
        self.s_t.issue_wait("[48]@[f4]sn[80]s"  # vpOption (control flags)
                            "[50]@[af]sn[00]s"  # vpClock (Sample Clock Ticks)
                            "[52]@[e8]sn[03]s"  # vpModulo (Table Modulo Size)
                            "[5e]@[0a]sn[01]s"  # vpMark (Mark Count/Phase)
                            "[60]@[01]sn[00]s"  # vpSpace (Space Count/Phase)
                            "[78]@[00]sn[7f]s"  # vrDacOutput (DAC Level)
                            "[46]@[02]s"  # vmCmd (Command Vector)
                            )
        self.s_t.issue_wait("Z")  # GENERATE!
        self.s_t.issue_wait(">")
        self.s_t.issue("U")
        self.ser.flushInput()

        self.state = self.s_waiting

    def s_waiting(self):  # Connected and doing nothing really.
        self.s_t.issue_wait("?")
        self.ser.flushInput()

    """Data Processing Functions"""
    """Update Functions"""

    def update(self):
        try:
            self.state()
        except serial.SerialException:
            print "Device disconected | Error: SE"
            self.state = self.s_find_device
        except serial.SerialTimeoutException:
            print "Device disconected | Error: STE"
            self.state = self.s_find_device
Esempio n. 5
0
class MachineVerify(object):
    def __init__(self):

        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False

        self.state = self.s_find_device

        self.trace_size = 1024 #captured trace size in samples.
        self.extra_trace = 16 #ADC warmup junk
        self.whole_trace = self.trace_size + self.extra_trace
        self.d_size = self.trace_size * 2 #dump size in bytes
        self.ex_size = self.extra_trace * 2 #extra samples for ADC warmup in bytes
        self.whole_dump = (self.trace_size + self.extra_trace) * 2

        self.data = {
            "device":{"model":None, "connected":False, "tested":False, "pass":False,
            "connected_not_tested":False},
            "test":{"status":"connect", "op_count":1},
            "ch":{"a":{}, "b":{}},
            "mask_height":5000,
            "masks":{ #Lists of tuples containing mask ranges.
                "comp":[(123,190)]
            },
            "cal_points":{
                "comp":{
                    "shape":[50,205,250],
                    "top":range(191,212)
                }
            },
            "mode":"pre_test",
            "sample_offset":{
                "comp":35,
                "adc":125,
                "logic":70
            },
        }
        self.data['ranges'] = {}
        self.data['ranges']['BS0005'] = {
            1.1 :           "[64]@[56]sn[7e]sn[77]sn[82]s",
            3.5 :           "[64]@[c3]sn[6a]sn[a3]sn[95]s",
            5.2 :           "[64]@[68]sn[44]sn[ff]sn[8a]s",
            11 :            "[64]@[6a]sn[12]sn[8c]sn[ba]s",
            "better_11" :   "[64]@[6f]sn[14]sn[8c]sn[ba]s",
            "max" :         "[64]@[00]sn[00]sn[ff]sn[ff]s"
        }

        self.data['ranges']['BS0010'] = {
            0.520:          "[64]@[40]sn[65]sn[82]sn[6c]s",
            1.1 :           "[64]@[14]sn[61]sn[6f]sn[70]s",
            3.5 :           "[64]@[5c]sn[50]sn[3a]sn[81]s",
            5.2 :           "[64]@[9d]sn[44]sn[38]sn[8d]s",
            11 :            "[64]@[28]sn[1c]sn[c1]sn[b5]s",
            "max" :         "[64]@[00]sn[00]sn[ff]sn[ff]s"
        }
        self.data['range'] = 11
        self.data['templates'] = {
            "comp":([19792] * 119) + ([480] * 152) + ([19762] * 151)
        }

        self.data['results'] = {
            "comp" : False,
            "adc"  : False,
            "logic": False,
            "test" : False
        }

        self.data['ch']['a'] = {
            "trace":[],
            "display_trace":[],
            "ena":False,
            "zero": {16:10131, 8:162},
            "sos": 0,
            "sos_string":"",
            "errors":{"shape":0, "top":0},
            "pass":{"comp":False, "adc":False},
            "limits":{"comp":30, "adc":100},
            "queue":[0]*5,
            "result":0,
            "ready":False,
            "frame_count":0,
            "ready_on_frame":5
        }
        
        # Clone ch a to ch b
        self.data['ch']['b'] = {}
        copy_dict(self.data['ch']['a'], self.data['ch']['b'])
        
        # Aliases
        self.ch = self.data['ch']
        self.a = self.ch['a']
        self.b = self.ch['b']
        self.dev = self.data['device']
        self.test = self.data['test']
        
    """API funcs"""
    def capture_trace(self, ch):
        if ch == "logic":
            print self.ch[ch]['traces']['combined']
        else:
            print self.ch[ch]['display_trace']
        # self.data['templates']['trace'] = self.ch[ch]['display_trace']
        
    def switch_operation(self, op):
        self.data['mode'] = op
        self.state = self.s_operation_router

    def reset_status(self):
        d = self.data
        dev = d['device']
        res = d['results']
        dev['connected_not_tested'] = False
        dev['model'] = dev['tested'] = dev['pass'] = False
        res['comp'] = False
        self.data['test']['status'] = 'connect'
        if self.data['mode'] == "post_test":
            self.data['mode'] = "pre_test"

    """STATES"""
    def s_operation_router(self):
        op = self.data['mode']
        test = self.data['test']
        if self.data['device']['connected']:
            if op == "post_test":
                self.state = self.s_post
                test['op_count'] = 4
            elif op == "pre_test":
                self.state = self.s_idle
                if test['status'] == 'proceed':
                    test['op_count'] = 2
            elif op == "comp":
                self.state = self.s_setup_for_comp
                test['op_count'] = 3
        else:
            self.state = self.s_find_device
    
    def s_find_device(self):
        if self.data['mode'] == "post_test":
            self.reset_status()
        elif self.data['mode'] == "pre_test":
            self.data['test']['status'] = 'connect'
            self.data['test']['op_count'] = 1
        else:
            self.data['test']['status'] = 'connect'

        self.ser = self.s_t.find_device()
        if self.ser != None:
            self.data['device']['connected'] = True
            self.state = self.s_check_model
        else:
            if self.data['device']['connected']:
                self.data['device']['connected'] = False
            self.state = self.s_find_device

    def s_check_model(self):
        self.ser.read(10000) #Try to get anything in the buffer.
        self.s_t.clear_waiting() #Force the counter to reset.
        self.s_t.issue_wait("?")
        self.data['device']['model'] = (self.ser.read(20)[1:7])
        print self.data['device']['model'] + " Connected."
        self.data['test']['status'] = "proceed"

        self.dirty = True
        if self.data['device']['model'] in self.data['ranges']:
            self.state = self.s_setup_bs
        else:
            self.state = self.s_check_model

    def s_setup_bs(self):
        bc = ""
        bc+="[1c]@[%s]sn[%s]s" % l_endian_hexify(self.whole_dump / 2) #Dump size
        bc+="[1e]@[05]s[21]@[12]s" #set dump and trace
        bc+="[08]@[00]sn[00]sn[00]s" #Set spock address
        bc+="[16]@[01]sn[00]s" #Set iterations to 1
        
        bc+="[2a]@[%s]sn[%s]s" % l_endian_hexify(self.whole_trace) #post trig cap 
        bc+="[30]@[00]s" #dump channel (Doesn't do anything?)
        bc+="[31]@[04]s" #Buffer mode (to macro)
        bc+="[37]@[00]s" #Analogue channel enable
        bc+="[26]@[%s]sn[%s]s" % l_endian_hexify(16) #pre trig cap
        bc+="[2c]@[00]sn[0a]s" #Time out REALLY IMPORTANT
        bc+="[2e]@[90]sn[00]s" #Set clock ticks
        bc+="[14]@[01]sn[00]s" #clock scale
        self.s_t.issue_wait(bc)
        """TRIGGER"""
        self.s_t.issue_wait(
            "[06]@[00]s" #Set trigger mask to "Don't care about anything"
            "[05]@[00]s" #This doesn't matter because we don't care about triggers.
            "[28]@[00]sn[00]s" #pre trigger delay
            "[32]@[00]sn[00]sn[00]sn[00]s" #Edge trigger intro, then outro filter.
            "[44]@[00]sn[00]s" #dig comparitor trigger (signed)
            "[40]@[00]sn[00]sn[00]sn[00]s" #stop watch trigger (ticks)
        )
        bc = (self.data['ranges'][self.data['device']['model']][self.data['range']]) #Range entry
        bc += "U"
        self.s_t.issue_wait(bc)
        
        """WAVE FORM GENERATOR"""
        self.s_t.issue_wait(
            "[7c]@[c0]s" # Kitchen sink register B! ENABLES AWG!!!
            "[86]@[00]s"  # Turn the clock generator off.
        )
        self.s_t.issue_wait("U")
        self.s_t.issue_wait(
            "[46]@[00]s"# vpCmd (Command Vector)
            "[47]@[03]s"# vpMode (Operating Mode)
            "[5a]@[00]sn[80]sn[00]sn[00]s"# vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("Y")# SYNTHESIZE!
        self.s_t.issue_wait(
            "[46]@[00]s"# vpCmd (Command Vector)
            "[47]@[00]s"# vpMode (Operating Mode)
            "[4a]@[e8]sn[03]s"# vpSize (Operation size, 1000 samples)
            "[4c]@[00]sn[00]s"# vpIndex (Operation Index, table start)
            "[4e]@[00]sn[00]s"# vpAddress (Destination Address, buffer start)
            "[54]@[ff]sn[ff]s"# vpLevel (Output Level, full scale)
            "[56]@[00]sn[00]s"# vpOffset (Output Offset, zero)
            "[5a]@[93]sn[18]sn[04]sn[00]s"# vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("X")# TRANSLATE!
        self.s_t.issue_wait(
            "[48]@[f4]sn[80]s"# vpOption (control flags)
            "[50]@[af]sn[00]s"# vpClock (Sample Clock Ticks)
            "[52]@[e8]sn[03]s"# vpModulo (Table Modulo Size)
            "[5e]@[0a]sn[01]s"# vpMark (Mark Count/Phase)
            "[60]@[01]sn[00]s"# vpSpace (Space Count/Phase)
            "[78]@[00]sn[7f]s"# vrDacOutput (DAC Level)
            "[46]@[02]s"# vmCmd (Command Vector)
        )
        self.s_t.issue_wait("Z")# GENERATE!
        self.ser.read(10000)
        self.s_t.issue_wait(">")
        self.s_t.issue("U")
        
        self.state = self.s_operation_router

    """Idle..........."""
    def s_idle(self):
        self.s_t.issue_wait("?")
        self.ser.flushInput()

    def s_post(self):
        dev = self.data['device']
        dev['tested'] = True
        res = self.data['results']
        dev['pass'] = res['comp']
        if dev['connected'] and dev['tested']:
            if dev['pass']:
                self.data['test']['status'] = "passed"
            else:
                self.data['test']['status'] = "failed"
        
        self.state = self.s_idle

    """COMP"""
    def s_setup_for_comp(self):
        self.s_t.issue_wait(
            "[1e]@[05]s[21]@[12]s" #set dump and trace mode
            "[31]@[04]s" #Buffer mode (to macro)
            "[2e]@[90]sn[00]s" # Clock ticks
        )
        self.s_t.issue_wait(self.data['ranges']['BS0005'][11]) #Range entry
        """AWG"""
        self.s_t.issue_wait("[7c]@[c0]s") # Kitchen sink register B! ENABLES AWG!!!
        self.s_t.issue_wait("[74]@[0f]s") # Logic pins to outputs.
        self.s_t.issue_wait("[86]@[00]s") # Turn the clock generator off.
        self.s_t.issue_wait(
            "[46]@[00]s"# vpCmd (Command Vector)
            "[47]@[03]s"# vpMode (Operating Mode)
            "[5a]@[00]sn[80]sn[00]sn[00]s"# vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("Y")# SYNTHESIZE!
        self.s_t.issue_wait(
            "[47]@[00]s"# vpMode (Operating Mode)
            "[5a]@[93]sn[18]sn[04]sn[00]s"# vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("X")# TRANSLATE!
        self.s_t.issue_wait(
            "[50]@[af]sn[00]s"# vpClock (Sample Clock Ticks)
            "[46]@[02]s"# vmCmd (Command Vector)
        )
        self.s_t.issue_wait("Z")# GENERATE!
        self.s_t.issue_wait(">")
        self.s_t.issue_wait("U")
        self.ser.read(1000)
        
        self.state = self.s_init_a_req

    # Use alternating capture! 
    def s_init_a_req(self):
        self.s_t.clear_waiting()
        self.ser.read(10000)
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[01]sD")

        self.state = self.s_a_dump

    def s_a_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)
        self.s_t.issue_wait(">")
        self.s_t.issue("A")

        self.state = self.s_a_proc_b_req

    def s_a_proc_b_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.ex_size)
        a_dump = self.ser.read(self.d_size)
        self.a['trace'] = convert_12bit_bin_dump(a_dump)
        self.a['ready'] = True

        self.s_t.issue_wait(">")
        self.s_t.issue("[07]@[04]s[37]@[02]sD")

        self.state = self.s_b_dump

    def s_b_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)
        self.s_t.issue_wait(">")
        self.s_t.issue("A")

        self.state = self.s_b_proc_a_req

    def s_b_proc_a_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.ex_size)
        b_dump = self.ser.read(self.d_size)
        self.b['trace'] = convert_12bit_bin_dump(b_dump)
        self.b['ready'] = True
        
        self.s_t.issue_wait(">")
        self.s_t.issue("[07]@[00]s[37]@[01]sD")

        self.state = self.s_a_dump            
        
    """Process funcs"""
    def find_trigger(self, ch):
        tr = self.ch[ch]['trace']

        if tr:
            zero = self.ch[ch]['zero'][16]

            count = 5
            for iii in range(50, len(tr)-count, 1): # 50 sample lead so we can move backwards later.
                pre_sum = 0
                post_sum = 0
                #Check previous samples are lower
                for prev in range(0,count-1,1):
                    pre_sum += tr[iii + prev]
                #Check proceeding samples are higher
                for post in range(1,count,1):
                    post_sum += tr[iii + post]

                post_avg = post_sum / (count)
                pre_avg = pre_sum / (count)

                if post_avg >= zero and pre_avg <= zero:
                    return iii

            return None
            
    def triggered_trace(self, ch):
        trigger = self.find_trigger(ch)
        if trigger is not None:
            offset = self.data['sample_offset'][self.data['mode']]
            self.ch[ch]['display_trace'] = self.ch[ch]['trace'][trigger+offset:] # offset backwards to 0
        else:
            self.ch[ch]['display_trace'] = self.ch[ch]['trace']

    def sum_of_squares(self, ch):
        temp = self.data['templates'][self.data['mode']]
        trace = self.ch[ch]['display_trace']
        error = self.ch[ch]['errors']['top']
        mask = self.data['mask_height']
        m2 = 500
        diff_sqr = 0.0
        count = 0
        if trace and (len(trace) >= len(temp)):
            for iii in range(len(temp)):
                if (temp[iii] < mask
                    and trace[iii] < mask
                    and (trace[iii-1] - trace[iii]) < m2
                    and (trace[iii+1] - trace[iii]) < m2):
                    diff_sqr += ((float(temp[iii] - error) - float(trace[iii]))**2) / 100.0
                    count += 1
            self.ch[ch]['sos_string'] = str("%.1f"%diff_sqr).rjust(5)
            if count:
                self.ch[ch]['sos'] = diff_sqr / count

    def check_error(self, ch, mode):
        temp = self.data['templates'][self.data['mode']]
        trace = self.ch[ch]['display_trace']
        temp_diff = 0
        if len(trace) > len(temp):
            for pt in self.data['cal_points'][self.data['mode']][mode]:
                temp_diff += temp[pt] - trace[pt]

            self.ch[ch]['errors'][mode] = temp_diff / len(self.data['cal_points'][self.data['mode']][mode])

    def test_error_value(self, ch):
        if abs(self.ch[ch]['errors']['shape']) >= 400:
            self.ch[ch]['pass']['comp'] = False

    def correct_error(self, ch): # Moves template wave around. Not used. :(
        temp = self.data['templates']['comp']
        err = self.ch[ch]['error']
        for iii in range(len(temp)-1):
            temp[iii] = temp[iii] - err

    def process_queue(self, ch):
        channel = self.ch[ch]
        channel['queue'].pop(0)
        channel['queue'].append(self.ch[ch]['sos'])
        if channel['frame_count'] == channel['ready_on_frame']:
            avg = sum(channel['queue']) / len(channel['queue'])
            channel['result'] = int(avg * 10) # *10 to make it pretty. No other reason.
            channel['frame_count'] = 0
        else:
            channel['frame_count'] += 1

    def check_pass(self, ch, op):
        channel = self.ch[ch]
        result = channel['result']
        limit = channel['limits'][op]
        if result <= limit:
            channel['pass'][op] = True
        else:
            channel['pass'][op] = False
        if result >= 10000:
            channel['result'] = "OVER"

    def check_operation_pass(self, op):
        d_ch = self.ch
        d_res = self.data['results']
        d_res['comp'] = d_ch['a']['pass']['comp'] and d_ch['b']['pass']['comp']
        
    """UPDATES"""
    def comp_update(self):
        if self.ch['a']['ready']:
            self.check_error('a', 'top')
            self.triggered_trace('a')
            self.sum_of_squares('a')
            self.process_queue('a')
            self.check_error('a', 'shape')
            self.check_pass('a', 'comp')
            self.test_error_value('a')
            self.ch['a']['ready'] = False

        if self.ch['b']['ready']:
            self.check_error('b', 'top')
            self.triggered_trace('b')
            self.sum_of_squares('b')
            self.process_queue('b')
            self.check_error('b', 'shape')
            self.check_pass('b', 'comp')
            self.test_error_value('b')
            self.ch['b']['ready'] = False

        self.check_operation_pass('comp')
            
    def update(self):
        if self.test['op_count'] == 2:
            self.dev['connected_not_tested'] = True
        else:
            self.dev['connected_not_tested'] = False
        
        try:
            self.state()
        except serial.SerialException:
            print "Device disconected | Error: SE"
            self.state = self.s_find_device
        except serial.SerialTimeoutException:
            print "Device disconected | Error: STE"
            self.state = self.s_find_device

        self.comp_update()
Esempio n. 6
0
class MachineTest(object):
    def __init__(self):

        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False

        self.state = self.s_find_device

        self.trace_size = 1024  # Captured trace size in samples.
        self.extra_trace = 16  # ADC warmup junk
        self.whole_trace = self.trace_size + self.extra_trace
        self.d_size = self.trace_size * 2  # Dump size in bytes
        self.ex_size = self.extra_trace * 2  # Extra samples for ADC warmup in bytes
        self.whole_dump = (self.trace_size + self.extra_trace) * 2

        self.data = {
            "device": {
                "model": None,
                "connected": False,
                "tested": False,
                "pass": False,
                "connected_not_tested": False
            },
            "test": {
                "status": "connect",
                "op_count": 1
            },
            "ch": {
                "a": {},
                "b": {}
            },
            "mask_height": 5000,
            "masks": {  # Lists of tuples containing mask ranges.
                "comp": [(123, 190)]
            },
            "cal_points": {
                "comp": {
                    "shape": [50, 205, 250],
                    "top": range(191, 212)
                }
            },
            "mode": "pre_test",
            "sample_offset": {
                "comp": 35,
                "adc": 125,
                "logic": 70
            },
        }
        self.data['ranges'] = {}
        self.data['ranges']['BS0005'] = {
            1.1: "[64]@[56]sn[7e]sn[77]sn[82]s",
            3.5: "[64]@[c3]sn[6a]sn[a3]sn[95]s",
            5.2: "[64]@[68]sn[44]sn[ff]sn[8a]s",
            11: "[64]@[6a]sn[12]sn[8c]sn[ba]s",
            "better_11": "[64]@[6f]sn[14]sn[8c]sn[ba]s",
            "max": "[64]@[00]sn[00]sn[ff]sn[ff]s"
        }

        self.data['ranges']['BS0010'] = {
            0.520: "[64]@[40]sn[65]sn[82]sn[6c]s",
            1.1: "[64]@[14]sn[61]sn[6f]sn[70]s",
            3.5: "[64]@[5c]sn[50]sn[3a]sn[81]s",
            5.2: "[64]@[9d]sn[44]sn[38]sn[8d]s",
            11: "[64]@[28]sn[1c]sn[c1]sn[b5]s",
            "max": "[64]@[00]sn[00]sn[ff]sn[ff]s"
        }
        self.data['range'] = 11
        self.data['templates'] = {
            "comp": ([19792] * 119) + ([480] * 152) + ([19762] * 151),
            "adc":
            float_range(189, 252, 1.15) + float_range(250, 47, -1.15) +
            float_range(47, 252, 1.15) + float_range(250, 188, -1.15),
            "logic": []
        }

        self.data['results'] = {
            "comp": True,
            "adc": True,
            "logic": True,
            "connection": True,
            "test": True
        }

        self.data['c_lost'] = ""

        self.data['ch']['a'] = {
            "trace": [],
            "display_trace": [],
            "ena": False,
            "zero": {
                16: 10131,
                8: 162
            },
            "sos": 0,
            "sos_string": "",
            "errors": {
                "shape": 0,
                "top": 0
            },
            "pass": {
                "comp": False,
                "adc": False
            },
            "limits": {
                "comp": 20,
                "adc": 100
            },
            "queue": [0] * 5,
            "result": 0,
            "ready": False,
            "frame_count": 0,
            "ready_on_frame": 5
        }

        self.data['ch']['logic'] = {
            "traces": {
                "combined": [],
                "triggered": [],
                "l": [[], [], [], [], [], [], [], []]
            },
            "error": {
                "a_b": False,
                "l4_l5": False,
                "staggered": False
            },
            "ready": False,
            "cal_points": [361, 485, 350, 450]
        }
        # Clone ch a to ch b
        self.data['ch']['b'] = {}
        copy_dict(self.data['ch']['a'], self.data['ch']['b'])

        # Aliases
        self.a = self.data['ch']['a']
        self.b = self.data['ch']['b']

        self.logic_traces = self.data['ch']['logic']['traces']

    """API funcs"""

    def capture_trace(self, ch):
        if ch == "logic":
            print self.data['ch'][ch]['traces']['combined']
        else:
            print self.data['ch'][ch]['display_trace']
        # self.data['templates']['trace'] = self.data['ch'][ch]['display_trace']

    def switch_operation(self, op):
        self.data['mode'] = op
        self.state = self.s_operation_router

    def reset_status(self):
        d = self.data
        dev = d['device']
        res = d['results']
        dev['connected_not_tested'] = False
        dev['tested'] = False
        dev['model'] = dev['pass'] = True
        res['comp'] = res['adc'] = res['logic'] = res['test'] = True
        res['connection'] = True
        self.data['c_lost'] = ''
        self.data['test']['status'] = 'connect'
        if self.data['mode'] == "post_test":
            self.data['mode'] = "pre_test"

    """STATES"""

    def s_operation_router(self):
        op = self.data['mode']
        test = self.data['test']
        if self.data['device']['connected']:
            if op == "post_test":
                self.state = self.s_post
                test['op_count'] = 6
            elif op == "pre_test":
                self.state = self.s_pre
                if self.data['test']['status'] == 'proceed':
                    test['op_count'] = 2
            elif op == "comp":
                self.state = self.s_setup_for_comp
                test['op_count'] = 3
            elif op == "adc":
                self.state = self.s_setup_for_adc
                test['op_count'] = 4
            elif op == "logic":
                self.state = self.s_setup_for_logic
                test['op_count'] = 5
        else:
            self.state = self.s_find_device

    def s_find_device(self):
        if self.data['mode'] != "post_test" and self.data['mode'] != "pre_test":
            self.data['results'][
                'connection'] = False  # This is a hack! Move it elsewhere!
            self.data['c_lost'] = self.data['mode']

        if self.data['mode'] == "post_test":
            self.reset_status()
        elif self.data['mode'] == "pre_test":
            self.data['test']['status'] = 'connect'
            self.data['test']['op_count'] = 1
            self.data['device']['connected_not_tested'] = False
        else:
            self.data['test']['status'] = 'connect'

        self.ser = self.s_t.find_device()
        if self.ser != None:
            self.data['device']['connected'] = True
            self.state = self.s_check_model
        else:
            if self.data['device']['connected']:
                self.data['device']['connected'] = False
            self.state = self.s_find_device

    def s_check_model(self):
        self.ser.read(10000)  # Try to get anything in the buffer.
        self.s_t.clear_waiting()  # Force the counter to reset.
        self.s_t.issue_wait("?")
        self.data['device']['model'] = (self.ser.read(20)[1:7])
        self.data['test']['status'] = "proceed"

        self.dirty = True
        if self.data['device']['model'] in self.data['ranges']:
            self.state = self.s_setup_bs
            print self.data['device']['model'] + " Connected."
        else:
            self.state = self.s_check_model

    def s_setup_bs(self):
        bc = ""
        bc += "[1c]@[%s]sn[%s]s" % l_endian_hexify(
            self.whole_dump / 2)  # Dump size
        bc += "[1e]@[05]s[21]@[12]s"  # Set dump and trace
        bc += "[08]@[00]sn[00]sn[00]s"  # Set spock address
        bc += "[16]@[01]sn[00]s"  # Set iterations to 1

        bc += "[2a]@[%s]sn[%s]s" % l_endian_hexify(
            self.whole_trace)  # Post trig cap
        bc += "[30]@[00]s"  # Dump channel (Doesn't do anything?)
        bc += "[31]@[04]s"  # Buffer mode (to macro)
        bc += "[37]@[00]s"  # Analogue channel enable
        bc += "[26]@[%s]sn[%s]s" % l_endian_hexify(16)  # Pre trig cap
        bc += "[2c]@[00]sn[0a]s"  # Time out REALLY IMPORTANT
        bc += "[2e]@[90]sn[00]s"  # Set clock ticks
        bc += "[14]@[01]sn[00]s"  # clock scale
        self.s_t.issue_wait(bc)
        """TRIGGER"""
        self.s_t.issue_wait(
            "[06]@[00]s"  # Set trigger mask to "Don't care about anything"
            "[05]@[00]s"  # This doesn't matter because we don't care about triggers.
            "[28]@[00]sn[00]s"  # Pre trigger delay
            "[32]@[00]sn[00]sn[00]sn[00]s"  # Edge trigger intro, then outro filter.
            "[44]@[00]sn[00]s"  # Dig comparitor trigger (signed)
            "[40]@[00]sn[00]sn[00]sn[00]s"  # stop watch trigger (ticks)
        )
        bc = (self.data['ranges'][self.data['device']['model']][
            self.data['range']])  #Range entry
        bc += "U"
        self.s_t.issue_wait(bc)
        """WAVE FORM GENERATOR"""
        self.s_t.issue_wait(
            "[7c]@[c0]s"  # Kitchen sink register B! ENABLES AWG!!!
            "[86]@[00]s"  # Turn the clock generator off.
        )
        self.s_t.issue_wait("U")
        self.s_t.issue_wait(
            "[46]@[00]s"  # vpCmd (Command Vector)
            "[47]@[03]s"  # vpMode (Operating Mode)
            "[5a]@[00]sn[80]sn[00]sn[00]s"  # vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("Y")  # SYNTHESIZE!
        self.s_t.issue_wait(
            "[46]@[00]s"  # vpCmd (Command Vector)
            "[47]@[00]s"  # vpMode (Operating Mode)
            "[4a]@[e8]sn[03]s"  # vpSize (Operation size, 1000 samples)
            "[4c]@[00]sn[00]s"  # vpIndex (Operation Index, table start)
            "[4e]@[00]sn[00]s"  # vpAddress (Destination Address, buffer start)
            "[54]@[ff]sn[ff]s"  # vpLevel (Output Level, full scale)
            "[56]@[00]sn[00]s"  # vpOffset (Output Offset, zero)
            "[5a]@[93]sn[18]sn[04]sn[00]s"  # vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("X")  # TRANSLATE!
        self.s_t.issue_wait("[48]@[f4]sn[80]s"  # vpOption (control flags)
                            "[50]@[af]sn[00]s"  # vpClock (Sample Clock Ticks)
                            "[52]@[e8]sn[03]s"  # vpModulo (Table Modulo Size)
                            "[5e]@[0a]sn[01]s"  # vpMark (Mark Count/Phase)
                            "[60]@[01]sn[00]s"  # vpSpace (Space Count/Phase)
                            "[78]@[00]sn[7f]s"  # vrDacOutput (DAC Level)
                            "[46]@[02]s"  # vmCmd (Command Vector)
                            )
        self.s_t.issue_wait("Z")  # GENERATE!
        self.ser.read(10000)
        self.s_t.issue_wait(">")
        self.s_t.issue("U")

        self.state = self.s_operation_router

    """Idle..........."""

    def s_idle(self):
        self.s_t.issue_wait("?")
        self.ser.flushInput()

    def s_pre(self):
        dev = self.data['device']
        dev['connected_not_tested'] = not dev['tested'] and dev['connected']
        self.state = self.s_idle

    def s_post(self):
        dev = self.data['device']
        dev['tested'] = True
        res = self.data['results']
        cl = self.data['c_lost']
        if cl == "comp":
            res['comp'] = res['adc'] = res['logic'] = 'nt'
        elif cl == "adc":
            res['adc'] = res['logic'] = 'nt'
        elif cl == "logic":
            res['logic'] = 'nt'
        dev['pass'] = res['comp'] and res['adc'] and res['logic'] and res[
            'connection']
        for p in res.values():
            if p == 'nt':
                dev['pass'] = False

        dev['connected_not_tested'] = not dev['tested'] and dev['connected']

        if dev['connected'] and dev['tested']:
            if dev['pass']:
                self.data['test']['status'] = "passed"
            else:
                self.data['test']['status'] = "failed"

        self.state = self.s_idle

    """COMP"""

    def s_setup_for_comp(self):
        self.s_t.issue_wait("[1e]@[05]s[21]@[12]s"  # Set dump and trace mode
                            "[31]@[04]s"  # Buffer mode (to macro)
                            "[2e]@[90]sn[00]s"  # Clock ticks
                            )
        self.s_t.issue_wait(self.data['ranges']['BS0005'][11])  #Range entry
        """AWG"""
        self.s_t.issue_wait(
            "[7c]@[c0]s")  # Kitchen sink register B! ENABLES AWG!!!
        self.s_t.issue_wait("[74]@[0f]s")  # Logic pins to outputs.
        self.s_t.issue_wait("[86]@[00]s")  # Turn the clock generator off.
        self.s_t.issue_wait(
            "[46]@[00]s"  # vpCmd (Command Vector)
            "[47]@[03]s"  # vpMode (Operating Mode)
            "[5a]@[00]sn[80]sn[00]sn[00]s"  # vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("Y")  # SYNTHESIZE!
        self.s_t.issue_wait(
            "[47]@[00]s"  # vpMode (Operating Mode)
            "[5a]@[93]sn[18]sn[04]sn[00]s"  # vpRatio (Phase Ratio)
        )
        self.s_t.issue_wait("X")  # TRANSLATE!
        self.s_t.issue_wait("[50]@[af]sn[00]s"  # vpClock (Sample Clock Ticks)
                            "[46]@[02]s"  # vmCmd (Command Vector)
                            )
        self.s_t.issue_wait("Z")  # GENERATE!
        self.s_t.issue_wait(">")
        self.s_t.issue_wait("U")
        self.ser.read(1000)

        self.state = self.s_init_a_req

    # Use alternating capture!
    def s_init_a_req(self):
        self.s_t.clear_waiting()
        self.ser.read(10000)
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[01]sD")

        self.state = self.s_a_dump

    def s_a_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)
        self.s_t.issue_wait(">")
        self.s_t.issue("A")

        self.state = self.s_a_proc_b_req

    def s_a_proc_b_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.ex_size)
        a_dump = self.ser.read(self.d_size)
        self.data['ch']['a']['trace'] = convert_12bit_bin_dump(a_dump)
        self.data['ch']['a']['ready'] = True

        self.s_t.issue_wait("[07]@[04]s")
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[02]sD")

        self.state = self.s_b_dump

    def s_b_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)
        self.s_t.issue_wait(">")
        self.s_t.issue("A")

        self.state = self.s_b_proc_a_req

    def s_b_proc_a_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.ex_size)
        b_dump = self.ser.read(self.d_size)
        self.data['ch']['b']['trace'] = convert_12bit_bin_dump(b_dump)
        self.data['ch']['b']['ready'] = True

        self.s_t.issue_wait("[07]@[00]s")
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[01]sD")

        self.state = self.s_a_dump

    """ADC"""

    def s_setup_for_adc(self):
        si = self.s_t.issue_wait
        siw = self.s_t.issue_wait
        ### General ###
        si("[1e]@[00]s[21]@[00]s"  # set dump and trace
           "[31]@[00]s"  # Buffer mode (to macro)
           "[64]@[54]sn[60]sn[42]sn[95]s"  # Set range (monopole-ish)
           "[2e]@[90]sn[00]s"  # Clock ticks
           )
        ### AWG ###
        siw("[7c]@[c0]s"  # Kitchen sink register B! ENABLES AWG!!!
            "[74]@[0f]s"  # Logic pins to outputs.
            "[86]@[00]s"  # Turn the clock generator off.
            # SYNTHESIZE!
            "[46]@[00]s"
            "[47]@[01]s"  # vpMode (Operating Mode)
            "[5a]@[00]sn[80]sn[00]sn[00]s"  # vpRatio (Phase Ratio)
            "Y")
        siw(
            # TRANSLATE!
            "[47]@[00]s"  # vpMode (Operating Mode)
            "[5a]@[93]sn[18]sn[04]sn[00]s"  # vpRatio (Phase Ratio)
            "X")
        siw(
            # GENERATE!
            "[50]@[cd]sn[00]s"  # vpClock (Sample Clock Ticks)
            "[46]@[02]s"  # vmCmd (Command Vector)
            "Z")
        siw(">")
        siw("U")
        self.s_t.clear_waiting()
        self.ser.flushInput()

        self.state = self.s_adc_init_a_req

    def s_adc_init_a_req(self):
        self.s_t.clear_waiting()
        self.ser.read(10000)
        self.s_t.issue_wait("[07]@[00]s")
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[01]sD")

        self.state = self.s_adc_a_dump

    def s_adc_a_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)
        self.s_t.issue_wait(">")
        self.s_t.issue("A")

        self.state = self.s_adc_a_proc_req

    def s_adc_a_proc_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.extra_trace)
        a_dump = self.ser.read(self.trace_size)
        self.data['ch']['a']['trace'] = convert_8bit_dump(a_dump)
        self.data['ch']['a']['ready'] = True

        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[01]sD")

        self.state = self.s_adc_a_dump

    """LOGIC"""

    def s_setup_for_logic(self):
        """General"""
        self.s_t.issue_wait("[1e]@[00]s[21]@[0e]s"  # set dump and trace
                            "[31]@[00]s"  # Buffer mode
                            "[2e]@[28]sn[00]s"  # Clock ticks
                            )
        """AWG"""
        self.s_t.issue_wait(
            "[7c]@[00]sU")  # Kitchen sink register B! Disables AWG!!!
        self.s_t.issue_wait("[74]@[00]sU")  # Logic pins to inputs.
        self.s_t.issue_wait(
            "[99]@[12]sU")  # vpMap (Enable clock 1 on output L5)
        self.s_t.issue_wait("[46]@[01]sZ")
        self.s_t.issue_wait(
            "[50]@[10]sn[27]s"  # vpClock (Master clock ticks per period, 20)
            "[82]@[00]sn[00]s"  # vpRise (Rising Edge at tick 0)
            "[84]@[88]sn[13]s"  # vpFall (Falling Edge at tick 10)
            "[86]@[80]s"  # vpControl (Enable Clock, select source 0)
            "[46]@[03]sn[00]sZ"  # vmCmd (Command Vector), GENERATE!    
        )
        self.s_t.issue_wait(">")
        self.s_t.issue_wait("U")
        self.ser.read(1000)

        self.state = self.s_logic_init_req

    def s_logic_init_req(self):
        self.s_t.clear_waiting()
        self.ser.read(1000)
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[80]sD")

        self.state = self.s_logic_dump

    def s_logic_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)
        self.s_t.issue_wait(">")
        self.s_t.issue("A")

        self.state = self.s_logic_proc_req

    def s_logic_proc_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.extra_trace)
        dump = self.ser.read(self.trace_size)
        self.logic_traces['combined'] = convert_logic_dump(dump)
        self.data['ch']['logic']['ready'] = True
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[80]sD")

        self.state = self.s_logic_dump

    """Process funcs"""

    def find_trigger(self, ch):
        if ch != "logic":
            tr = self.data['ch'][ch]['trace']
        else:
            tr = self.data['ch'][ch]['traces']['combined']
        if tr:
            if self.data['mode'] == "comp":
                zero = self.data['ch'][ch]['zero'][16]

                count = 5
                for iii in range(
                        50,
                        len(tr) - count,
                        1):  # 50 sample lead so we can move backwards later.
                    pre_sum = 0
                    post_sum = 0
                    # Check previous samples are lower
                    for prev in range(0, count - 1, 1):
                        pre_sum += tr[iii + prev]
                    # Check proceeding samples are higher
                    for post in range(1, count, 1):
                        post_sum += tr[iii + post]

                    post_avg = post_sum / (count)
                    pre_avg = pre_sum / (count)

                    if post_avg >= zero and pre_avg <= zero:
                        return iii

                return None

            elif self.data['mode'] == "adc":
                for iii in range(50, len(tr) - 10, 1):
                    sur = (tr[iii - 1] + tr[iii] + tr[iii + 1]) / 3
                    if (sur < tr[iii - 5] and sur < tr[iii + 5]
                            and tr[iii] < 55):
                        return iii
                return None

            elif self.data['mode'] == "logic":
                for iii in range(1, len(tr) - 1, 1):
                    if (tr[iii - 1][2] == 0 and tr[iii][2] == 1):
                        return iii
                return None

    def triggered_trace(self, ch):
        trigger = self.find_trigger(ch)
        if trigger is not None:
            offset = self.data['sample_offset'][self.data['mode']]
            if ch != "logic":
                self.data['ch'][ch]['display_trace'] = self.data['ch'][ch][
                    'trace'][trigger + offset:]  # offset backwards to 0
            else:
                self.data['ch'][ch]['traces']['triggered'] = self.data['ch'][
                    ch]['traces']['combined'][trigger + offset:]
        else:
            if ch != "logic":
                self.data['ch'][ch]['display_trace'] = self.data['ch'][ch][
                    'trace']
            else:
                self.data['ch'][ch]['traces']['triggered'] = self.data['ch'][
                    ch]['traces']['combined']

    def sum_of_squares(self, ch):
        template = self.data['templates'][self.data['mode']]
        trace = self.data['ch'][ch]['display_trace']
        error = self.data['ch'][ch]['errors']['top']
        max_level = self.data[
            'mask_height']  # Max value a sample can be to be considered
        max_diff = 500  # Max acceptable diff between two samples
        diff_sqr = 0.0
        samples_to_inspect = 100
        count = 0
        if trace and (len(trace) >= len(template)):
            for iii in range(len(template)):
                if (template[iii] < max_level and trace[iii] < max_level
                        and (trace[iii - 1] - trace[iii]) <
                        max_diff  # Check we're 2 sample into the flat
                        and count <= samples_to_inspect):
                    diff_sqr += ((float(template[iii] - error) -
                                  float(trace[iii]))**2) / 100.0
                    count += 1
                elif count > samples_to_inspect:
                    break
            self.data['ch'][ch]['sos_string'] = str("%.1f" % diff_sqr).rjust(5)
            if count:
                self.data['ch'][ch]['sos'] = diff_sqr / count

    def sum_of_squares_adc(self, ch):
        temp = self.data['templates'][self.data['mode']]
        trace = self.data['ch'][ch]['display_trace']
        diff_sqr = 0.0
        if trace and (len(trace) >= len(temp)):
            for iii in range(len(temp)):
                diff_sqr += ((float(temp[iii]) - float(trace[iii]))**2) / 5
            self.data['ch'][ch]['sos'] = diff_sqr / len(temp)

    def check_logic_stagger(self):
        prev_fall = None
        log = self.data['ch']['logic']['traces']['l']
        err = self.data['ch']['logic']['error']
        for iii in range(3, 8):
            prev_fall = self.find_fall(iii - 1)
            if prev_fall is not None:
                if log[iii][prev_fall] != 1:
                    err['staggered'] = True
                else:
                    err['staggered'] = False

    def check_logic_points(self):
        pts = self.data['ch']['logic']['cal_points']
        tr = self.data['ch']['logic']['traces']['l']
        err = self.data['ch']['logic']['error']
        error = False
        for bit in (0, 1, 2, 3):
            val = 0
            tr_bit = tr[bit]
            for p in pts:
                if tr_bit[p] != val:
                    error = True
                val = not val
            if bit == 0 or bit == 1:
                err['a_b'] = error
                if bit == 1:
                    error = False
            else:
                err['l4_l5'] = error

    def find_fall(self, trace):
        log = self.data['ch']['logic']['traces']['l'][trace]
        for iii in range(10, len(log)):
            if log[iii] == 0 and log[iii - 1] == 1:
                return iii

    def check_error(self, ch, mode):
        temp = self.data['templates'][self.data['mode']]
        trace = self.data['ch'][ch]['display_trace']
        temp_diff = 0
        if len(trace) > len(temp):
            for pt in self.data['cal_points'][self.data['mode']][mode]:
                temp_diff += temp[pt] - trace[pt]
            self.data['ch'][ch]['errors'][mode] = temp_diff / len(
                self.data['cal_points'][self.data['mode']][mode])

    def test_error_value(self, ch):
        if abs(self.data['ch'][ch]['errors']['shape']) >= 400:
            self.data['ch'][ch]['pass']['comp'] = False

    def correct_error(self, ch):  # Moves template wave around. Not used. :(
        temp = self.data['templates']['comp']
        err = self.data['ch'][ch]['error']
        for iii in range(len(temp) - 1):
            temp[iii] = temp[iii] - err

    def process_queue(self, ch):
        channel = self.data['ch'][ch]
        channel['queue'].pop(0)
        channel['queue'].append(self.data['ch'][ch]['sos'])
        if channel['frame_count'] == channel['ready_on_frame']:
            avg = sum(channel['queue']) / len(channel['queue'])
            channel['result'] = int(
                avg * 10)  # *10 to make it pretty. No other reason.
            channel['frame_count'] = 0
        else:
            channel['frame_count'] += 1

    def process_logic(self):
        # Separate each bit position into a stream.
        trig = self.logic_traces['triggered']
        if trig:
            log = self.logic_traces['l']
            for stream in range(len(log)):
                t = []
                for sample in trig:
                    t.append(int(sample[stream]))
                log[stream] = t

    def check_pass(self, ch, op):
        channel = self.data['ch'][ch]
        result = channel['result']
        limit = channel['limits'][op]
        if result <= limit:
            channel['pass'][op] = True
        else:
            channel['pass'][op] = False
        if result >= 10000:
            channel['result'] = "OVER"

    def check_operation_pass(self, op):
        d_ch = self.data['ch']
        d_res = self.data['results']
        if op == "comp":
            d_res['comp'] = d_ch['a']['pass']['comp'] and d_ch['b']['pass'][
                'comp']
        elif op == "adc":
            d_res['adc'] = d_ch['a']['pass']['adc']
        elif op == "logic":
            log_err = d_ch['logic']['error']
            a_b = not log_err['a_b']
            l4_l5 = not log_err['l4_l5']
            stag = not log_err['staggered']
            d_res['logic'] = a_b and l4_l5 and stag

        self.data['device']['pass'] = all(self.data['results'].values())

    """UPDATES"""

    def comp_update(self):
        if self.data['ch']['a']['ready']:
            self.check_error('a', 'top')
            self.triggered_trace('a')
            self.sum_of_squares('a')
            self.process_queue('a')
            self.check_error('a', 'shape')
            self.check_pass('a', 'comp')
            self.test_error_value('a')
            self.data['ch']['a']['ready'] = False

        if self.data['ch']['b']['ready']:
            self.check_error('b', 'top')
            self.triggered_trace('b')
            self.sum_of_squares('b')
            self.process_queue('b')
            self.check_error('b', 'shape')
            self.check_pass('b', 'comp')
            self.test_error_value('b')
            self.data['ch']['b']['ready'] = False

        self.check_operation_pass('comp')

    def adc_update(self):
        if self.data['ch']['a']['ready']:
            self.triggered_trace('a')
            self.sum_of_squares_adc('a')
            self.process_queue('a')
            self.check_pass('a', 'adc')
            self.data['ch']['a']['ready'] = False
            self.check_operation_pass('adc')

    def logic_update(self):
        if self.data['ch']['logic']['ready']:
            self.triggered_trace("logic")
            self.process_logic()
            self.check_logic_points()
            self.check_logic_stagger()
            self.check_operation_pass('logic')

    def update(self):
        try:
            self.state()
        except serial.SerialException:
            print "Device disconected | Error: SE"
            self.state = self.s_find_device
        except serial.SerialTimeoutException:
            print "Device disconected | Error: STE"
            self.state = self.s_find_device

        if self.data['mode'] == "comp":
            self.comp_update()
        elif self.data['mode'] == "adc":
            self.adc_update()
        elif self.data['mode'] == "logic":
            self.logic_update()
Esempio n. 7
0
class MachineXYPlot(object):
    def __init__(self):
        """Serial Setup"""
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False

        self.state = self.s_find_device

        self.trace_size = 1024
        self.extra_trace = 4
        self.whole_trace = self.trace_size + self.extra_trace
        self.dump_size = self.trace_size
        self.extra_dump = self.extra_trace
        self.whole_dump = self.dump_size + self.extra_dump
        """Data exposed through API"""
        self.data = {
            "device": {
                "connected": False,
                "model": None
            },
            "accepted_models": ["BS0005", "BS0010"],
            "trace": []
        }

        self.a_d, self.b_d = [], []

    """API Functions"""
    """States"""

    def s_find_device(self):
        self.ser = self.s_t.find_device()
        if self.ser != None:
            self.data['device']['connected'] = True
            self.state = self.s_check_model
        else:
            if self.data['device']['connected']:
                self.data['device']['connected'] = False
            self.state = self.s_find_device

    def s_check_model(self):
        self.ser.flushInput  # Try to get anything in the buffer.
        self.s_t.clear_waiting()  # Force the counter to reset.
        self.s_t.issue_wait("?")
        model = (self.ser.read(20)[1:7])
        self.data['device']['model'] = model
        print self.data['device']['model'] + " Connected."

        self.dirty = True
        if model in self.data['accepted_models']:
            self.state = self.s_setup_bs
        else:
            self.state = self.s_check_model

    def s_setup_bs(self):
        si = self.s_t.issue
        siw = self.s_t.issue_wait
        si("[1c]@[%s]sn[%s]s" %
           (l_endian_hexify(self.whole_dump)))  # Dump size
        si("[1e]@[00]s[21]@[02]s")  # Dump/Trace = Filter/Macro
        si("[08]@[00]sn[00]sn[00]s")  # Spock address
        si("[16]@[01]sn[00]s")  # Iterations = 1

        si("[2a]@[%s]sn[%s]s" %
           (l_endian_hexify(self.whole_trace)))  # Post trig cap (was 1024)
        si("[30]@[00]s")  # Dump channel
        si("[31]@[01]s")  # Buffer mode chop
        si("[37]@[03]s")  # Analogue channel enable
        si("[26]@[%s]sn[%s]s" %
           (l_endian_hexify(self.whole_trace)))  # Pre trig cap
        si("[2c]@[00]sn[0f]s")  # Time out REALLY IMPORTANT
        si("[2e]@[28]sn[00]s")  # Set clock ticks (ticks(6us steps) per sample)
        si("[14]@[01]sn[00]s")  # Clock scale
        """TRIGGER"""
        si("[06]@[00]s")  # Set trigger mask to "Don't care about anything"
        si("[05]@[00]s"
           )  # This doesn't matter because we don't care about triggers.
        """Filter mode stuff"""
        #self.issue("[18]@[10]sn[00]s") # Dump send to 16
        #self.issue("[1a]@[00]sn[00]s") # skip = 0 (sum 16, skip 0, sum 16, skip 0, ...)

        r_high, r_low = to_span(2.0, 4.0)
        siw("[64]@[%s]sn[%s]s" % l_endian_hexify(r_low))  # Range low
        siw("[66]@[%s]sn[%s]s" % l_endian_hexify(r_high))  # Range high
        self.ser.read(1000)

        siw(">")
        siw("U")

        self.state = self.s_change_to_chop

    def s_change_to_chop(self):
        si = self.s_t.issue
        siw = self.s_t.issue_wait
        self.ser.read(1000)
        self.s_t.clear_waiting()
        si("[1e]@[00]s")  # Set dump mode
        si("[21]@[02]s")  # Set trace mode
        si("[31]@[01]s")  # Buffer mode
        si("[37]@[03]s")  # Ana ch enable

        siw(">")
        siw("U")

        self.state = self.s_pre_idle

    def s_pre_idle(self):
        self.s_t.clear_waiting()
        self.ser.read(1000)
        self.state = self.s_idle

    def s_idle(self):  #Idle
        self.s_t.issue_wait("check")
        self.state = self.s_init_req

    """Dual chop"""

    def s_init_req(self):
        self.s_t.clear_waiting()
        self.ser.read(10000)
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[03]sD")
        self.state = self.s_a_dump

    def s_a_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)
        self.s_t.issue_wait(">")
        self.s_t.issue("[30]@[00]sA")  # Dump chA

        self.state = self.s_a_proc_b_dump

    def s_a_proc_b_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(self.extra_trace)
        self.a_d = self.ser.read(self.dump_size)
        self.s_t.issue_wait(">")
        self.s_t.issue("[30]@[01]sA")  # Dump chA

        self.state = self.s_b_proc_a_b_req

    def s_b_proc_a_b_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.extra_trace)
        self.b_d = self.ser.read(self.dump_size)
        self.s_t.issue_wait(">")
        self.s_t.issue("[37]@[03]sD")  # Req both

        self.generate_lissajous()

        self.state = self.s_a_dump

    """Data Processing Functions"""

    def generate_lissajous(self):
        a = map(ord, self.a_d)
        b = map(ord, self.b_d)
        line = []
        for i in range(0, len(a) - 1):
            # line.append([(a[i])*(490/256), (b[i])*(490/256)])
            line.append([(a[i]), (b[i])])
        self.data['trace'] = line

    """Update Functions"""

    def update(self):
        try:
            self.state()
        except serial.SerialException:
            print "Device disconected | Error: SE"
            self.state = self.s_find_device
        except serial.SerialTimeoutException:
            print "Device disconected | Error: STE"
            self.state = self.s_find_device