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 = [], []
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()
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"] }
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 = {}
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
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 }
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
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
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()
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()
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
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']
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']
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
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()
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