Beispiel #1
0
    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 = [], []
Beispiel #2
0
class MachineTuner(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
        """Data exposed through API"""
        self.data = {
            "device": {
                "connected": False,
                "model": None
            },
            "accepted_models": ["BS0005", "BS0010"]
        }

    """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
        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):
        pass

    """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
    def __init__(self):
        """Serial Setup"""
        self.ready = False
        self.trace_state=0
        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":1,
            "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()
Beispiel #4
0
    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
        """Data exposed through API"""
        self.data = {
            "device": {
                "connected": False,
                "model": None
            },
            "accepted_models": ["BS0005", "BS0010"]
        }
Beispiel #5
0
 def __init__(self, ser):
     self.ser = ser
     self.st = Serial_Tools(self.ser)
     """ Dict of all the BS's state.
     This way, if it disconnects, we know exactly how to set it up.
     This is assuming the BS was setup entirely through this...
     """
     self.registers = {}
Beispiel #6
0
    def __init__(self, name, cfg):
        self.name = name
        self.cfg = cfg
        self.mode_cfg = cfg['modes'][name]
        """Serial Setup"""
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False
        self.command = ""

        self.state = self.s_find_device

        self.position = 0
        self.max = 10000000

        """Data exposed through API"""
        self.data = {
            "device":{"connected":False, "model":None},
            "accepted_models":["BS0005", "BS0010"],
            "status":"stopped",
            "streaming":False,
            "stream_mode":0, # Analogue A, or logic
            "trace":[],
            "ba":bytearray(1024*1024*10),
            "ba":bytearray(100000),
            "ba_pos":0,
            "ba_range":1000,
            "data_ready":False,
            "deep_scan":False,
            "range_high":200000,
            "range_low":100,
            "ba_zoom":(0,0),
            "frequency":100, # khz
            "interval":0, # us
            "file_mode":0
        }
        self.data['ba_zoom'] = (0, len(self.data['ba']))
        self.data['interval'] = int(freq_to_ns(self.data['frequency']) / 1000)
    def __init__(self):
        """ Serial """
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False
        """ Trace and dump settings """
        self.trace_size = 512  # Size in samples (2 bytes)
        self.extra_trace = 16
        self.whole_trace = self.trace_size + self.extra_trace

        self.dump_compression = 16  # The BitScope will compress 16 samples to 1
        self.dump_size = (self.trace_size /
                          self.dump_compression) * 2  # Size in bytes
        self.extra_dump = (self.extra_trace / self.dump_compression) * 2
        self.whole_dump = (self.whole_trace / self.dump_compression) * 2
        """ API Data """
        self.data = {
            "device": {
                "connected": False,
                "model": None
            },
            "accepted_models": ["BS0005", "BS0010"],
            "dump": [],
            "voltage": 0.0,
            "voltage_text": "",
            "dump_ready": False,
            "channel": "a",
            "ch_a_zero": 0.0,
            "ch_b_zero": 0.0,
        }
        self.data['ranges'] = {
            "BS0005": (-5.28, 8.11),  # <1% error
            "BS0010": (-4.84, 10.8)  # Not sure on this one!
        }
        self.command = ""

        self.state = self.s_find_device
        self.range_in_use = None
Beispiel #8
0
    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
        }
Beispiel #9
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
Beispiel #10
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
Beispiel #11
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()
Beispiel #12
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()
Beispiel #13
0
class MachineLogic(object):
    def __init__(self, name, cfg):
        self.name = name
        self.cfg = cfg
        self.mode_cfg = cfg['modes'][name]
        """Serial Setup"""
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False
        self.command = ""

        self.state = self.s_find_device

        self.position = 0
        self.max = 10000000

        """Data exposed through API"""
        self.data = {
            "device":{"connected":False, "model":None},
            "accepted_models":["BS0005", "BS0010"],
            "status":"stopped",
            "streaming":False,
            "stream_mode":0, # Analogue A, or logic
            "trace":[],
            "ba":bytearray(1024*1024*10),
            "ba":bytearray(100000),
            "ba_pos":0,
            "ba_range":1000,
            "data_ready":False,
            "deep_scan":False,
            "range_high":200000,
            "range_low":100,
            "ba_zoom":(0,0),
            "frequency":100, # khz
            "interval":0, # us
            "file_mode":0
        }
        self.data['ba_zoom'] = (0, len(self.data['ba']))
        self.data['interval'] = int(freq_to_ns(self.data['frequency']) / 1000)

    """API Functions"""
    def start_capture(self):
        self.command += "T"
        self.state = self.s_capture
        
    def pause_capture(self):
        self.command += "."
        self.state = self.s_idle
        self.data['ba_zoom'] = (0,len(self.data['ba']))
        
    def stop_capture(self):
        self.command += "."
        self.state = self.s_idle
        self.data['ba_zoom'] = (0,len(self.data['ba']))
        
    def stop_start(self):
        status = self.data['status']
        if self.state == self.s_idle or self.state == self.s_capture:
            if status == "stopped":
                self.data['data_ready'] = False
                self.data['status'] = "capturing"
                self.data['streaming'] = True
                # self.state = self.start_capture
                self.start_capture()
            elif status == "paused":
                self.data['data_ready'] = False
                self.data['status'] = "capturing"
                self.data['streaming'] = True
                # self.state = self.start_capture
                self.start_capture()
            elif status == "capturing":
                self.data['data_ready'] = True
                self.data['status'] = "stopped"
                self.data['streaming'] = False
                # self.state = self.stop_capture
                self.stop_capture()
        
    def set_sample_frequency(self, freq):
        self.data['frequency'] = freq
        self.data['interval'] = int(freq_to_ns(freq))
        self.command = ("[2e]@[%s]sn[%s]s" % l_endian_hexify(self.data['interval'] / 25))
        self.data['interval'] /= 1000 # Convert to us
        
    def inc_sample_frequency(self, inc):
        freq = self.data['frequency']
        freq = int(inc_125_pattern(freq, inc))
        if (1 <= freq <= 500): # If the value is okay
            self.set_sample_frequency(freq) # Set it!
            
    def clear_data(self):
        self.data['ba'] = bytearray(100000)
        self.data['ba_zoom'] = (0, len(self.data['ba']))
        self.data['ba_range'] = 1000
        self.data['ba_pos'] = 0
        self.data['data_ready'] = 100 # To ensure redraw no matter true or false
        self.position = 0
        
    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)
        
    def inc_ba_pos(self, inc):
        self.data['ba_pos'] += int(inc)
        self.data['ba_pos'] = self.check_position(self.data['ba_pos'])
        
    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)
                 
    def zoom_ba(self):
        sd = self.data
        zoom = sd['ba_pos'], sd['ba_pos'] + sd['ba_range']
        if zoom[1] - zoom[0] >= 1000:
            sd['ba_zoom'] = zoom
        
    def reset_zoom_ba(self):
        sd = self.data
        sd['ba_zoom'] = 0, len(sd['ba'])
    
    def do_deep_scan(self):
        self.data['deep_scan'] = not self.data['deep_scan']
        
    def inc_file_format(self, inc):
        last_mode = 3
        new_mode = self.data['file_mode'] + inc
        if new_mode > last_mode:
            new_mode = 0
        elif new_mode < 0:
            new_mode = last_mode
        self.data['file_mode'] = new_mode
        
    def dump_to_file(self):
        file_name = time.strftime("%Y-%m-%d_%H:%M:%S")
        mode = self.data['file_mode']
        extension = "txt"
        replace_chars = []
        
        if mode == 0: # Raw
            file_name = "bin_" + file_name
            to_write = self.data['ba'][:self.position]
        elif mode == 1: # CSV decimal
            file_name = "dec_" + file_name
            to_write = str([int(b) for b in self.data['ba'][:self.position]])
            replace_chars = ["[", "]"]
        elif mode == 2: # CSV hex
            file_name = "hex_" + file_name
            to_write = str([hex(b)[2:] for b in self.data['ba'][:self.position]])
            replace_chars = ["'", "[", "]"]
        elif mode == 3: # Sigrok session
            file_name = "sr_" + file_name
            extension = "sr"
            data = self.data['ba'][:self.position]
            sr = sigrok_session.SigrokSession()
            sr.set_rate(self.data['frequency'] * 1000)
            sr.set_data(data)
            to_write = sr.get_session_file().getvalue()
                   
        for ch in replace_chars:
            to_write = to_write.replace(ch, "")
        
        directory = os.path.dirname(self.cfg['globals']['output_dir'])
        if not os.path.exists(directory):
            os.makedirs(directory)
        
        with open(directory + "/" + file_name + '.' + extension, 'wb') as out:
            out.write(to_write)
            
    def toggle_stream_mode(self):
        sm = self.data['stream_mode']
        if sm == 0:
            self.set_stream_mode(1)
        elif sm == 1:
            self.set_stream_mode(0)
        
    def set_stream_mode(self, mode):
        self.data['stream_mode'] = mode
        if mode == 1:
            self.command = "[37]@[01]sn[00]s>"
        elif mode == 0:
            self.command = "[37]@[00]sn[ff]s>"
        
    """States"""
    def s_find_device(self):
        self.data['streaming'] = False
        self.data['status'] = "stopped"
        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

    def s_setup_bs(self):
        si = self.s_t.issue
        siw = self.s_t.issue_wait
        self.command = "" # Clear command buffer
        siw("!") # Reset
        si(
            "[21]@[02]s" # Trace mode (change to logic!)
            "[14]@[01]sn[00]s" # Clock scale
            # "[74]@[00]s" # Logic pins to inputs
        )
        self.set_stream_mode(self.data['stream_mode'])
        mch_cfg = self.mode_cfg['machine_cfg']
        high, low = to_span(mch_cfg['offset'], mch_cfg['range'])
        si("[66]@[%s]sn[%s]s" % l_endian_hexify(high))
        si("[64]@[%s]sn[%s]s" % l_endian_hexify(low))
        intervals = int(freq_to_ns(self.data['frequency']) / 25)
        si("[2e]@[%s]sn[%s]s" % l_endian_hexify(intervals)) # Clock ticks
        siw("U")
        siw(">")
        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_capture(self):
        if self.command and self.ser:
            self.s_t.issue_wait(self.command)
            self.command = ""
        in_count = self.ser.inWaiting()
        if in_count:
            new_ba = self.ser.read(in_count)
            self.alter_bytearray(new_ba)
            if self.position >= self.max:
                self.stop_start()
            

    """Data Processing Functions"""
    def alter_bytearray(self, new_data):
        # No for-loop version
        self.data['ba'][self.position:self.position + len(new_data)] = new_data
        self.position += len(new_data)
            
    """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
        except IOError:
            print "Some other IO fault"
            self.state = self.s_find_device
Beispiel #14
0
    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']
Beispiel #15
0
    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']
Beispiel #16
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
Beispiel #17
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
class MachineSimpleMeter(object):
    def __init__(self):
        """ Serial """
        self.ser = None
        self.s_t = Serial_Tools(self.ser)
        self.s_t.show_messages = False
        """ Trace and dump settings """
        self.trace_size = 512  # Size in samples (2 bytes)
        self.extra_trace = 16
        self.whole_trace = self.trace_size + self.extra_trace

        self.dump_compression = 16  # The BitScope will compress 16 samples to 1
        self.dump_size = (self.trace_size /
                          self.dump_compression) * 2  # Size in bytes
        self.extra_dump = (self.extra_trace / self.dump_compression) * 2
        self.whole_dump = (self.whole_trace / self.dump_compression) * 2
        """ API Data """
        self.data = {
            "device": {
                "connected": False,
                "model": None
            },
            "accepted_models": ["BS0005", "BS0010"],
            "dump": [],
            "voltage": 0.0,
            "voltage_text": "",
            "dump_ready": False,
            "channel": "a",
            "ch_a_zero": 0.0,
            "ch_b_zero": 0.0,
        }
        self.data['ranges'] = {
            "BS0005": (-5.28, 8.11),  # <1% error
            "BS0010": (-4.84, 10.8)  # Not sure on this one!
        }
        self.command = ""

        self.state = self.s_find_device
        self.range_in_use = None

    """ API Functions """

    def zero_current_channel(self):
        ch_zero_string = "ch_" + self.data['channel'] + "_zero"
        self.data[ch_zero_string] += self.data['voltage']

    def change_channel(self):
        if self.data['channel'] == 'a':
            self.data['channel'] = 'b'
            num = 2
        else:
            self.data['channel'] = 'a'
            num = 1

        self.s_t.issue("[30]@[0" + str(num - 1) + "]s")
        self.s_t.issue("[37]@[0" + str(num) + "]s")
        self.s_t.issue_wait(">")

    """ Helpers """

    def ch_char_to_number(self, ch):
        return (1 if ch == 'a' else 2)

    """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):
        d = self.data
        si = self.s_t.issue
        siw = self.s_t.issue_wait
        leh = l_endian_hexify
        ch_num = self.ch_char_to_number(d['channel'])
        self.range_in_use = self.data['ranges'][self.data['device']['model']]
        siw("!")
        si("[1c]@[%s]sn[%s]s" % leh(self.whole_dump / 2)  # Dump size (samples)
           + "[2a]@[%s]sn[%s]s" % leh(self.whole_trace)  # Post trig (samples)
           + "[26]@[%s]sn[%s]s" % leh(self.extra_trace)  # Pre trig (samples)
           + "[1e]@[06]s[21]@[12]s"  # Dump/Trace = Filter/Macro
           + "[16]@[01]sn[00]s"  # Iterations = 1
           + "[31]@[04]s"  # Buffer mode = macro
           + "[08]@[00]sn[00]sn[00]s"  # Spock address = 0
           + "[30]@[0" + str(ch_num - 1) + "]s"  # Dump channel
           + "[37]@[0" + str(ch_num) + "]s"  # Analogue channel enable
           + "[2c]@[00]sn[0a]s"  # Time out = 10
           + "[2e]@[90]sn[01]s"  # Clock ticks = 400
           + "[14]@[01]sn[00]s"  # Clock scale = 1
           # 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
           )
        siw(">")
        siw("U")
        self.state = self.s_idle

    def s_idle(self):
        self.s_t.clear_waiting()
        self.s_t.issue_wait("?")
        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")  # Trace selected channel

        self.state = self.s_dump

    def s_dump(self):
        self.s_t.clear_waiting()
        self.ser.read(33)  # Dispose of the trace's aux information
        self.s_t.issue_wait(">")
        self.s_t.issue("A")  # Dump selected channel
        self.data['dump_ready'] = False

        self.state = self.s_process_and_req

    def s_process_and_req(self):
        self.s_t.clear_waiting()
        self.ser.read(self.extra_dump)
        self.data['dump'] = convert_12bit_bin_dump(
            self.ser.read(self.dump_size))
        self.data['dump_ready'] = True

        self.s_t.issue_wait(">")
        self.s_t.issue("D")

        self.state = self.s_dump

    """ Data Processing Functions """

    def derive_voltage(self):
        d = self.data
        avg = sum(d['dump']) / len(d['dump'])
        # Map 16 bit range to voltage range
        d['voltage'] = to_range(avg, (-32768, 32767), self.range_in_use)
        d['voltage'] -= d['ch_' + d['channel'] + '_zero']
        print d

    def set_voltage_text(self):  # Move this stuff to view somehow!
        d = self.data
        reduce_to = "%." + '3' + "f"  # Max length of voltage is 8 chars
        d['voltage_text'] = (reduce_to % d['voltage'] + "v").rjust(8)

    """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

        if self.data['dump_ready']:
            self.derive_voltage()
            self.set_voltage_text()
Beispiel #19
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