From d361fe8f5117c3c46586e3a42d7a3311467addea Mon Sep 17 00:00:00 2001 From: "Michael D. M. Dryden" Date: Wed, 22 Nov 2017 14:17:16 -0500 Subject: [PATCH 1/2] Add manual mode. Needs dstat-interface@1a40c83 --- dstat_interface/core/experiments/chronoamp.py | 133 +++++++++++++++++- dstat_interface/core/interface/exp_int.py | 59 +++++++- dstat_interface/core/interface/exp_window.py | 1 + dstat_interface/main.py | 2 + 4 files changed, 190 insertions(+), 5 deletions(-) diff --git a/dstat_interface/core/experiments/chronoamp.py b/dstat_interface/core/experiments/chronoamp.py index 5998178..56417cd 100644 --- a/dstat_interface/core/experiments/chronoamp.py +++ b/dstat_interface/core/experiments/chronoamp.py @@ -2,9 +2,12 @@ import time import struct import numpy as np import serial +from copy import deepcopy + +from .experiment_template import PlotBox, Experiment, exp_logger, dstat_logger from ..interface.plot import mean, plotSpectrum, findBounds +from ..dstat import state -from .experiment_template import PlotBox, Experiment, exp_logger class ChronoampBox(PlotBox): def format_plots(self): @@ -63,10 +66,132 @@ class Chronoamp(Experiment): if newline is True: self.data['current_time'].append(deepcopy(self.line_data)) + try: + for i, item in enumerate(self.data['current_time'][line]): + item.append(data[i]) + except IndexError: + pass + +class ManExp(Chronoamp): + id = 'man' + """Manual experiment""" + def setup(self): + self.handler_ids = [self.parameters['exp_window'].connect('new_voltage', self.new_voltage), + self.parameters['exp_window'].connect('new_gain', self.new_gain)] + + self.plots.append(ManBox('current_time')) + + self.datatype = "linearData" + self.datalength = 2 + self.databytes = 8 + self.data = {'current_time': [([], [], [])]} + self.line_data = ([], [], []) + self.columns = ['Time (s)', 'Current (A)', 'Voltage (mV)'] + self.plot_format = { + 'current_time': { + 'labels': self.columns, + 'xlims': (0, 10) + } + } + + self.commands.append("EN") + + def new_voltage(self, widget, voltage): + state.ser.send_ctrl("v{}\n".format(int(voltage*(65536./3000)+32768))) + + def new_gain(self, widget): + state.ser.send_ctrl("g{}\n".format(self.parameters['adc_pot'].params['gain'])) + + def serial_handler(self): + """Handles incoming serial transmissions from DStat. Returns False + if stop button pressed and sends abort signal to instrument. Sends + data to self.data_pipe as result of self.data_handler). + """ + + def check_ctrl(): + if self.ctrl_pipe.poll(): + input = self.ctrl_pipe.recv() + exp_logger.info("serial_handler: %s", input) + if input == "DISCONNECT": + self.serial.write('a') + self.serial.reset_input_buffer() + exp_logger.info("serial_handler: ABORT pressed!") + time.sleep(.3) + return False + elif input == 'a': + self.serial.write('a') + else: + self.serial.write(input) + + scan = 0 + voltage = 0 + + try: + while True: + check_ctrl() + + for line in self.serial: + check_ctrl() + + if line.startswith('B'): + data = self.data_handler( + (scan, voltage, self.serial.read(size=self.databytes))) + data = self.data_postprocessing(data) + if data is not None: + self.data_pipe.send(data) + try: + self.datapoint += 1 + except AttributeError: # Datapoint counting is optional + pass + + elif line.lstrip().startswith('S'): + scan += 1 + + elif line.lstrip().startswith('G'): + self.gain = self.parameters["gain_table"][int(line.split(" ")[1])] + + elif line.lstrip().startswith('V'): + voltage = int(line.split(" ")[1]) + + elif line.lstrip().startswith("#"): + dstat_logger.info(line.lstrip().rstrip()) + + elif line.lstrip().startswith("@DONE"): + dstat_logger.debug(line.lstrip().rstrip()) + time.sleep(.3) + return True + + except serial.SerialException: + return False + + def data_handler(self, data_input): + """Overrides Experiment method to not convert x axis to mV.""" + scan, voltage, data = data_input + # 2*uint16 + int32 + seconds, milliseconds, current = struct.unpack(' Date: Wed, 22 Nov 2017 19:41:08 -0500 Subject: [PATCH 2/2] Desensitize manual controls while experiment not ready. --- dstat_interface/core/dstat/comm.py | 4 ++-- dstat_interface/core/dstat/dfu.py | 1 + dstat_interface/core/experiments/chronoamp.py | 23 +++++++++++++------ .../core/experiments/experiment_template.py | 1 + dstat_interface/core/interface/exp_int.py | 20 +++++++++++++++- dstat_interface/core/interface/exp_window.py | 4 +++- dstat_interface/main.py | 2 +- 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/dstat_interface/core/dstat/comm.py b/dstat_interface/core/dstat/comm.py index d78ea58..66903c8 100755 --- a/dstat_interface/core/dstat/comm.py +++ b/dstat_interface/core/dstat/comm.py @@ -192,7 +192,7 @@ class SerialConnection(GObject.Object): def get_proc(self, block=False): self.assert_connected() - + if block is True: return self.proc_pipe_p.recv() else: @@ -211,7 +211,7 @@ class SerialConnection(GObject.Object): return self.ctrl_pipe_p.recv() else: return None - + def get_data(self, block=False): self.assert_connected() diff --git a/dstat_interface/core/dstat/dfu.py b/dstat_interface/core/dstat/dfu.py index 3b56288..101b9da 100755 --- a/dstat_interface/core/dstat/dfu.py +++ b/dstat_interface/core/dstat/dfu.py @@ -278,6 +278,7 @@ def test_firmware_version(current=None): logger.error('Unexpected git error. Git exited {}'.format(test)) return False, None + def dfu_program(path='./dstat-firmware.hex'): """Tries to program DStat over USB with DFU with hex file at path.""" try: diff --git a/dstat_interface/core/experiments/chronoamp.py b/dstat_interface/core/experiments/chronoamp.py index 56417cd..bce5ecb 100644 --- a/dstat_interface/core/experiments/chronoamp.py +++ b/dstat_interface/core/experiments/chronoamp.py @@ -72,6 +72,7 @@ class Chronoamp(Experiment): except IndexError: pass + class ManExp(Chronoamp): id = 'man' """Manual experiment""" @@ -132,8 +133,8 @@ class ManExp(Chronoamp): for line in self.serial: check_ctrl() - - if line.startswith('B'): + line_in = line.lstrip() + if line_in.startswith('B'): data = self.data_handler( (scan, voltage, self.serial.read(size=self.databytes))) data = self.data_postprocessing(data) @@ -144,19 +145,22 @@ class ManExp(Chronoamp): except AttributeError: # Datapoint counting is optional pass - elif line.lstrip().startswith('S'): + elif line_in.startswith('S'): scan += 1 - elif line.lstrip().startswith('G'): + elif line_in.startswith('G'): self.gain = self.parameters["gain_table"][int(line.split(" ")[1])] - elif line.lstrip().startswith('V'): + elif line_in.startswith('V'): voltage = int(line.split(" ")[1]) - elif line.lstrip().startswith("#"): + elif line_in.startswith("#"): dstat_logger.info(line.lstrip().rstrip()) - elif line.lstrip().startswith("@DONE"): + elif line_in.startswith("R"): + self.ctrl_pipe.send("R") + + elif line_in.startswith("@DONE"): dstat_logger.debug(line.lstrip().rstrip()) time.sleep(.3) return True @@ -164,6 +168,10 @@ class ManExp(Chronoamp): except serial.SerialException: return False + def ctrl_loop(self, data): + if data == 'R': + self.emit('exp_ready') + def data_handler(self, data_input): """Overrides Experiment method to not convert x axis to mV.""" scan, voltage, data = data_input @@ -181,6 +189,7 @@ class ManExp(Chronoamp): super(ManExp, self).experiment_done() for i in self.handler_ids: self.parameters['exp_window'].disconnect(i) + self.emit('exp_done') class ManBox(ChronoampBox): def redraw(self): diff --git a/dstat_interface/core/experiments/experiment_template.py b/dstat_interface/core/experiments/experiment_template.py index bd36ce5..9fab05d 100755 --- a/dstat_interface/core/experiments/experiment_template.py +++ b/dstat_interface/core/experiments/experiment_template.py @@ -69,6 +69,7 @@ class Experiment(GObject.Object): b'exp_ready': (GObject.SIGNAL_RUN_FIRST, None, ()), b'exp_done': (GObject.SIGNAL_RUN_FIRST, None, ()) } + def __init__(self, parameters): """Adds commands for gain and ADC.""" super(Experiment, self).__init__() diff --git a/dstat_interface/core/interface/exp_int.py b/dstat_interface/core/interface/exp_int.py index 4a68475..6f26ece 100755 --- a/dstat_interface/core/interface/exp_int.py +++ b/dstat_interface/core/interface/exp_int.py @@ -214,7 +214,7 @@ class Manual(ExpInterface): self.window.set_vexpand(True) grid = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL) - grid.set_column_homogeneous(False) + grid.set_column_homogeneous(True) entries = OrderedDict([ ('voltage', 'Voltage (mV)'), @@ -236,8 +236,26 @@ class Manual(ExpInterface): grid.attach(gain_button, 0, n, 2, 1) gain_button.connect('clicked', self.new_gain) + self.buttons = [voltage_button, gain_button] + for i in self.buttons: + i.set_sensitive(False) + self.window.add(grid) + def exp_ready(self, widget): + for i in self.buttons: + i.set_sensitive(True) + + def exp_done(self, widget): + for i in self.buttons: + i.set_sensitive(False) + + def get_experiment(self, parameters): + exp = super(Manual, self).get_experiment(parameters) + exp.connect('exp_ready', self.exp_ready) + exp.connect('exp_done', self.exp_done) + return exp + def new_voltage(self, widget): self.emit('new_voltage', int(self.entry['voltage'].get_text())) diff --git a/dstat_interface/core/interface/exp_window.py b/dstat_interface/core/interface/exp_window.py index 9f7f25a..9f977da 100755 --- a/dstat_interface/core/interface/exp_window.py +++ b/dstat_interface/core/interface/exp_window.py @@ -33,11 +33,13 @@ from . import exp_int logger = logging.getLogger(__name__) + class Experiments(GObject.Object): __gsignals__ = { 'run_utility': (GObject.SIGNAL_RUN_FIRST, None, ()), 'done_utility': (GObject.SIGNAL_RUN_FIRST, None, ()) } + def __init__(self, builder): super(Experiments,self).__init__() self.builder = builder @@ -96,7 +98,7 @@ class Experiments(GObject.Object): exp.name) ) return exp.get_experiment(parameters) - + def hide_exps(self): for key in self.containers: self.containers[key].hide() diff --git a/dstat_interface/main.py b/dstat_interface/main.py index ff49410..febd0ba 100755 --- a/dstat_interface/main.py +++ b/dstat_interface/main.py @@ -640,7 +640,7 @@ class Main(object): self.current_exp.ctrl_loop(ctrl_buffer) except AttributeError: pass - + proc_buffer = dstat.state.ser.get_proc() if proc_buffer is not None: if proc_buffer in ["DONE", "SERIAL_ERROR", "ABORT"]: -- GitLab