Skip to content
#!/usr/bin/env python
# DStat Interface - An interface for the open hardware DStat potentiostat
# Copyright (C) 2014 Michael D. M. Dryden -
# Wheeler Microfluidics Laboratory <http://microfluidics.utoronto.ca>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import logging
from uuid import uuid4
try:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
except ImportError:
print "ERR: GTK not available"
sys.exit(1)
logger = logging.getLogger(__name__)
class DB_Window(GObject.GObject):
__gsignals__ = {
'db-reset' : (GObject.SIGNAL_RUN_LAST,
GObject.TYPE_NONE,
(GObject.TYPE_STRING,)
)
}
def __init__(self):
GObject.GObject.__init__(self)
self.builder = Gtk.Builder()
self.builder.add_from_file('interface/db.glade')
self.builder.connect_signals(self)
self.window = self.builder.get_object('db_window')
# Make sure window isn't destroyed if checkbox hit.
self.window.connect('delete-event', self.on_delete_event)
self.db_control_table = self.builder.get_object('db_control_table')
ui_keys = ['exp_id_entry',
'measure_id_entry',
'patient_id_entry',
'measure_name_entry',
'db_path_entry',
'db_apply_button',
'exp_id_autogen_button',
'db_enable_checkbutton'
]
self.persistent_keys = ['db_path_entry','db_enable_checkbutton']
self.ui = {}
for i in ui_keys:
self.ui[i] = self.builder.get_object(i)
self.metadata_map = [('experiment_uuid', 'exp_id_entry'),
('patient_id', 'patient_id_entry'),
('name', 'measure_name_entry')]
self._params = {}
@property
def persistent_params(self):
"""Dict of parameters that should be saved."""
self._get_params()
return {k:self._params[k] for k in self.persistent_keys}
@property
def params(self):
"""Dict of parameters."""
self._get_params()
return self._params
def _get_params(self):
"""Updates self._params from UI."""
for i in self.ui:
if i.endswith('checkbutton'):
self._params[i] = self.ui[i].get_active()
elif i.endswith('entry'):
text = self.ui[i].get_text()
if text == "":
text = None
self._params[i] = text
@params.setter
def params(self, params):
if self._params is {}:
self._params = dict.fromkeys(self.ui.keys())
for i in self._params:
if i in params:
self._params[i] = params[i]
self._set_params()
def _set_params(self):
"""Updates UI with new parameters."""
for i in self.ui:
if i.endswith('checkbutton'):
self.ui[i].set_active(self._params[i])
elif i.endswith('entry'):
if self._params[i] is not None:
self.ui[i].set_text(self._params[i])
else:
self.ui[i].set_text("")
def update_from_metadata(self, metadata):
params = {k : metadata[j] for j, k in self.metadata_map
if j in metadata}
self.params = params
def show(self):
self.window.show_all()
self.on_db_enable_checkbutton_toggled()
def on_db_enable_checkbutton_toggled(self, *args):
if self.ui['db_enable_checkbutton'].get_active():
self.db_control_table.show()
else:
self.db_control_table.hide()
def on_exp_id_autogen_button_clicked(self, *args):
self.ui['exp_id_entry'].set_text(uuid4().hex)
def on_db_apply_button_clicked(self, widget=None, *data):
self.emit('db-reset', self.params['db_path_entry'])
def on_delete_event(self, widget=None, *data):
widget.hide()
return True
GObject.type_register(DB_Window)
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkEntry" id="clean_s">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="dep_s">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="dep_mV">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="clean_mV">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Deposition</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Cleaning</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Time (s)</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Potential (mV)</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Preconditioning</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Start (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Stop (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Step Size (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="start_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="stop_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="step_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Pulse Height (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Pulse Width (ms)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="pulse_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="width_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Scan both forwards and backwards.</property>
<property name="label" translatable="yes">Pulse Period (ms)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="period_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Experiment</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Note: ADC samples 1/(ADC Frequency) before end of pulse. 1/(ADC frequency) should be significantly shorter than pulse period to reduce capacitive current.</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<property name="width_chars">43</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkAboutDialog" id="aboutdialog1">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="program_name">DStat-interface</property>
<property name="copyright" translatable="yes">© Michael Dryden 2014</property>
<property name="comments" translatable="yes">This software is licensed under the GNU GPL v3</property>
<property name="website">http://microfluidics.utoronto.ca/dstat</property>
<property name="website_label" translatable="yes">Wheeler Microfuidics Lab</property>
<property name="authors">Michael Dryden
Thanks to Christian Fobel for help with Dropbot Plugin</property>
<property name="documenters"/>
<property name="logo_icon_name">image-missing</property>
<property name="license_type">gpl-3-0</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<object class="GtkTextBuffer" id="databuffer1"/>
<object class="GtkTextBuffer" id="databuffer2"/>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="stock">gtk-missing-image</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">image7</property>
</object>
<object class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="image5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-open</property>
</object>
<object class="GtkImage" id="image6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-preferences</property>
</object>
<object class="GtkImage" id="image7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">image7</property>
</object>
<object class="GtkImage" id="image8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="image9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">image7</property>
</object>
<object class="GtkListStore" id="serial_liststore">
<columns>
<!-- column-name serial -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="border_width">6</property>
<property name="title" translatable="yes">Main</property>
<property name="default_width">1200</property>
<property name="default_height">800</property>
<signal name="destroy" handler="on_window1_destroy" swapped="no"/>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkMenuBar" id="menubar1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="menuitem1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">File</property>
<child type="submenu">
<object class="GtkMenu" id="menu1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="file_save_exp">
<property name="label" translatable="yes">Save Experiment Data…</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image8</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_file_save_exp_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="file_save_plot">
<property name="label" translatable="yes">Save Plot…</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image3</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_file_save_plot_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="file_save_params">
<property name="label" translatable="yes">Save Parameters…</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image4</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_file_save_params_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="file_load_params">
<property name="label" translatable="yes">Load Parameters…</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image5</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_file_load_params_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="gtk_quit">
<property name="label">gtk-quit</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_gtk_quit_activate" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menu_dstat">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">DStat</property>
<child type="submenu">
<object class="GtkMenu" id="menu5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="menu_dstat_info">
<property name="label">System Information</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image7</property>
<property name="use_stock">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="menu_dstat_fw">
<property name="label" translatable="yes">Firmware…</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image2</property>
<property name="use_stock">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="menu_dstat_reset">
<property name="label">Reset EEPROM</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image9</property>
<property name="use_stock">False</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menu_dropbot">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Dropbot</property>
<child type="submenu">
<object class="GtkMenu" id="menu2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="menu_dropbot_connect">
<property name="label">gtk-connect</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_menu_dropbot_connect_activate" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="menu_dropbot_disconnect">
<property name="label">gtk-disconnect</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_menu_dropbot_disconnect_activate" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menu_analysis">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Analysis</property>
<child type="submenu">
<object class="GtkMenu" id="menu4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="menu_analysis_options">
<property name="label" translatable="yes">Analysis Options…</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image6</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_menu_analysis_options_activate" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menuitem4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">About</property>
<child type="submenu">
<object class="GtkMenu" id="menu3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="gtk_about">
<property name="label">gtk-about</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_gtk_about_activate" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkPaned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="position">300</property>
<property name="position_set">True</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="gain_adc_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Experiment:</property>
<attributes>
<attribute name="weight" value="semibold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">10</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkComboBoxText" id="expcombobox">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="exp_section_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="pot_start">
<property name="label">gtk-execute</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_pot_start_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="pot_stop">
<property name="label">gtk-stop</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_pot_stop_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSpinner" id="spinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="exp_progressbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="show_text">True</property>
<property name="margin_top">10</property>
<property name="margin_bottom">15</property>
<property name="margin_right">5</property>
<property name="margin_left">2</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkNotebook" id="main_notebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="scrollable">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkNotebook" id="plot_notebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tab_pos">bottom</property>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">-1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<child>
<object class="GtkCheckButton" id="autosave_checkbutton">
<property name="label" translatable="yes">Autosave</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="autosavedir_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="action">select-folder</property>
<property name="preview_widget_active">False</property>
<property name="title" translatable="yes">Select a Save Folder</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="autosavename">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_tooltip">True</property>
<property name="valign">start</property>
<property name="max_length">32</property>
<property name="invisible_char"></property>
<property name="text" translatable="yes">filename</property>
<property name="caps_lock_warning">False</property>
<property name="primary_icon_stock">gtk-file</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_tooltip_text" translatable="yes">File name</property>
<property name="primary_icon_tooltip_markup" translatable="yes">File name</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Plot</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkStatusbar" id="statusbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Serial Port:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="serial_combobox">
<property name="width_request">128</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="model">serial_liststore</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="serial_connect">
<property name="label">gtk-connect</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_serial_connect_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="pmt_mode">
<property name="label" translatable="yes">Connect (PMT mode)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_serial_connect_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="serial_disconnect">
<property name="label">gtk-disconnect</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_serial_disconnect_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="serial_refresh">
<property name="label">gtk-refresh</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_serial_refresh_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ocp_disp">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">OCP:</property>
<property name="single_line_mode">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">3</property>
<property name="position">7</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkAdjustment" id="updatesamples_adj">
<property name="upper">100</property>
<property name="value">5</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
</interface>
#!/usr/bin/env python
# DStat Interface - An interface for the open hardware DStat potentiostat
# Copyright (C) 2014 Michael D. M. Dryden -
# Wheeler Microfluidics Laboratory <http://microfluidics.utoronto.ca>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import division, absolute_import, print_function, unicode_literals
import os
import sys
import logging
try:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
except ImportError:
print("ERR: GTK not available")
sys.exit(1)
from ..dstat import comm, state
from ..experiments import (cal, chronoamp, cv, experiment_template,
idle, lsv, pot, swv)
import __main__
from ..errors import InputError, VarError
logger = logging.getLogger(__name__)
mod_dir = os.path.dirname(os.path.abspath(__file__))
class ExpInterface(GObject.Object):
"""Generic experiment interface class. Should be subclassed to implement
experiment interfaces by populating self.entry. Override class attributes
to set id and experiment class to run.
"""
__gsignals__ = {
b'run_utility': (GObject.SIGNAL_RUN_FIRST, None, ()),
b'done_utility': (GObject.SIGNAL_RUN_FIRST, None, ())
}
id = None
experiment = None
def __init__(self, glade_path):
super(ExpInterface, self).__init__()
self.builder = Gtk.Builder()
self.builder.add_from_file(glade_path)
self.builder.connect_signals(self)
self.entry = {} # to be used only for str parameters
self._params = None
def get_experiment(self, parameters):
return self.__class__.experiment(parameters)
def _fill_params(self):
self._params = dict.fromkeys(self.entry.keys())
@property
def params(self):
"""Dict of parameters"""
if self._params is None:
self._fill_params()
self._get_params()
return self._params
def _get_params(self):
"""Updates self._params from UI."""
for i in self.entry:
self._params[i] = self.entry[i].get_text()
@params.setter
def params(self, params):
if self._params is None:
self._fill_params()
for i in self._params:
try:
self._params[i] = params[i]
except KeyError as e:
logger.warning("Invalid parameter key: %s" % e)
self._set_params()
def _set_params(self):
"""Updates UI with new parameters."""
for i in self.entry:
self.entry[i].set_text(self._params[i])
def get_window(self):
return self.builder.get_object('scrolledwindow1')
def on_run_utility(self, data=None):
self.emit('run_utility')
def on_done_utility(self, data=None):
self.emit('done_utility')
class Chronoamp(ExpInterface):
"""Experiment class for chronoamperometry. Extends ExpInterface class to
support treeview neeeded for CA.
Public methods:
on_add_button_clicked(self, widget)
on_remove_button_clicked(self, widget)
get_params(self)
"""
id = 'cae'
experiment = chronoamp.Chronoamp
def __init__(self):
"""Extends superclass method to support treeview."""
super(Chronoamp, self).__init__(os.path.join(mod_dir, 'chronoamp.glade'))
self.name = "Chronoamperometry"
self.statusbar = self.builder.get_object('statusbar')
self.model = self.builder.get_object('ca_list')
self.treeview = self.builder.get_object('treeview')
self.treeview.set_fixed_height_mode(False)
for i, column_title in enumerate(["Potential", "Time"]):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
column.set_expand(True)
self.treeview.append_column(column)
self.selection = self.treeview.get_selection()
self.selection.set_mode(Gtk.SelectionMode.MULTIPLE)
def _fill_params(self):
super(Chronoamp, self)._fill_params()
self._params['potential'] = []
self._params['time'] = []
def on_add_button_clicked(self, widget):
"""Add current values in potential_entry and time_entry to model."""
self.statusbar.remove_all(0)
try:
potential = int(
self.builder.get_object('potential_entry').get_text())
time = int(self.builder.get_object('time_entry').get_text())
if not state.board_instance.test_mv(potential):
raise ValueError("Potential out of range")
if not state.board_instance.test_s(time):
raise ValueError("Time out of range")
self.model.append([potential, time])
except ValueError as err:
self.statusbar.push(0, str(err))
except TypeError as err:
self.statusbar.push(0, str(err))
def on_remove_button_clicked(self, widget):
"""Remove currently selected items from model."""
# returns 2-tuple: treemodel, list of paths of selected rows
selected_rows = list(self.selection.get_selected_rows()[1])
referencelist = []
for i in selected_rows:
referencelist.append(Gtk.TreeRowReference(self.model, i))
for i in referencelist:
self.model.remove(self.model.get_iter(i.get_path()))
def _get_params(self):
"""Updates self._params from UI. Overrides superclass method."""
self._params['potential'] = [int(r[0]) for r in self.model]
self._params['time'] = [int(r[1]) for r in self.model]
def _set_params(self):
"""Updates UI from self._params. Overrides superclass method."""
self.model.clear()
table = zip(self._params['potential'], self._params['time'])
for i in table:
self.model.append(i)
class LSV(ExpInterface):
"""Experiment class for LSV."""
id = 'lsv'
experiment = lsv.LSVExp
def __init__(self):
"""Adds entry listings to superclass's self.entry dict"""
super(LSV, self).__init__(os.path.join(mod_dir, 'lsv.glade'))
self.name = "Linear Sweep Voltammetry"
self.entry['clean_mV'] = self.builder.get_object('clean_mV')
self.entry['clean_s'] = self.builder.get_object('clean_s')
self.entry['dep_mV'] = self.builder.get_object('dep_mV')
self.entry['dep_s'] = self.builder.get_object('dep_s')
self.entry['start'] = self.builder.get_object('start_entry')
self.entry['stop'] = self.builder.get_object('stop_entry')
self.entry['slope'] = self.builder.get_object('slope_entry')
class CV(ExpInterface):
"""Experiment class for CV."""
id = 'cve'
experiment = cv.CVExp
def __init__(self):
"""Adds entry listings to superclass's self.entry dict"""
super(CV, self).__init__(os.path.join(mod_dir, 'cv.glade'))
self.name = "Cyclic Voltammetry"
self.entry['clean_mV'] = self.builder.get_object('clean_mV')
self.entry['clean_s'] = self.builder.get_object('clean_s')
self.entry['dep_mV'] = self.builder.get_object('dep_mV')
self.entry['dep_s'] = self.builder.get_object('dep_s')
self.entry['start'] = self.builder.get_object('start_entry')
self.entry['v1'] = self.builder.get_object('v1_entry')
self.entry['v2'] = self.builder.get_object('v2_entry')
self.entry['slope'] = self.builder.get_object('slope_entry')
self.entry['scans'] = self.builder.get_object('scans_entry')
class SWV(ExpInterface):
"""Experiment class for SWV."""
id = 'swv'
experiment = swv.SWVExp
def __init__(self):
"""Adds entry listings to superclass's self.entry dict"""
super(SWV, self).__init__(os.path.join(mod_dir, 'swv.glade'))
self.name = "Square Wave Voltammetry"
self.entry['clean_mV'] = self.builder.get_object('clean_mV')
self.entry['clean_s'] = self.builder.get_object('clean_s')
self.entry['dep_mV'] = self.builder.get_object('dep_mV')
self.entry['dep_s'] = self.builder.get_object('dep_s')
self.entry['start'] = self.builder.get_object('start_entry')
self.entry['stop'] = self.builder.get_object('stop_entry')
self.entry['step'] = self.builder.get_object('step_entry')
self.entry['pulse'] = self.builder.get_object('pulse_entry')
self.entry['freq'] = self.builder.get_object('freq_entry')
self.entry['scans'] = self.builder.get_object('scans_entry')
def _fill_params(self):
super(SWV, self)._fill_params()
self._params['cyclic_true'] = False
def _get_params(self):
"""Updates self._params from UI."""
super(SWV, self)._get_params()
self._params['cyclic_true'] = self.builder.get_object(
'cyclic_checkbutton').get_active()
def _set_params(self):
"""Updates UI with new parameters."""
super(SWV, self)._set_params()
self.builder.get_object('cyclic_checkbutton').set_active(
self._params['cyclic_true'])
class DPV(ExpInterface):
"""Experiment class for DPV."""
id = 'dpv'
experiment = swv.DPVExp
def __init__(self):
"""Adds entry listings to superclass's self.entry dict"""
super(DPV, self).__init__(os.path.join(mod_dir, 'dpv.glade'))
self.name = "Differential Pulse Voltammetry"
self.entry['clean_mV'] = self.builder.get_object('clean_mV')
self.entry['clean_s'] = self.builder.get_object('clean_s')
self.entry['dep_mV'] = self.builder.get_object('dep_mV')
self.entry['dep_s'] = self.builder.get_object('dep_s')
self.entry['start'] = self.builder.get_object('start_entry')
self.entry['stop'] = self.builder.get_object('stop_entry')
self.entry['step'] = self.builder.get_object('step_entry')
self.entry['pulse'] = self.builder.get_object('pulse_entry')
self.entry['period'] = self.builder.get_object('period_entry')
self.entry['width'] = self.builder.get_object('width_entry')
# class ACV(ExpInterface):
# """Experiment class for ACV."""
# id = 'acv'
# def __init__(self):
# """Adds entry listings to superclass's self.entry dict"""
# super(ACV, self).__init__('interface/acv.glade')
# self.name = "AC Voltammetry"
#
# self.entry['start'] = self.builder.get_object('start_entry')
# self.entry['stop'] = self.builder.get_object('stop_entry')
# self.entry['slope'] = self.builder.get_object('slope_entry')
# self.entry['amplitude'] = self.builder.get_object('amplitude_entry')
# self.entry['freq'] = self.builder.get_object('freq_entry')
class PD(ExpInterface):
"""Experiment class for PD."""
id = 'pde'
experiment = chronoamp.PDExp
def __init__(self):
"""Adds entry listings to superclass's self.entry dict"""
super(PD, self).__init__(os.path.join(mod_dir, 'pd.glade'))
self.name = "Photodiode/PMT"
self.entry['time'] = self.builder.get_object('time_entry')
self.entry['sync_freq'] = self.builder.get_object('sync_freq')
self.entry['fft_start'] = self.builder.get_object('fft_entry')
self.entry['fft_int'] = self.builder.get_object('fft_int_entry')
self.buttons = map(self.builder.get_object,
['light_button', 'threshold_button'])
self.shutter_buttons = map(
self.builder.get_object,
['sync_button', 'sync_freq', 'fft_label', 'fft_entry', 'fft_label2',
'fft_int_entry']
)
bool_keys = ['interlock_true', 'shutter_true', 'sync_true']
bool_cont = map(self.builder.get_object,
['interlock_button',
'shutter_button',
'sync_button']
)
self.bool = dict(zip(bool_keys, bool_cont))
def _fill_params(self):
super(PD, self)._fill_params()
for i in self.bool:
self._params[i] = self.bool[i].get_active()
self._params['voltage'] = 0
def _get_params(self):
"""Updates self._params from UI."""
super(PD, self)._get_params()
for i in self.bool:
self._params[i] = self.bool[i].get_active()
self._params['voltage'] = self.builder.get_object(
'voltage_adjustment').get_value()
def _set_params(self):
"""Updates UI with new parameters."""
super(PD, self)._set_params()
for i in self.bool:
self.bool[i].set_active(self._params[i])
self.builder.get_object('voltage_adjustment').set_value(
self._params['voltage'])
def on_light_button_clicked(self, data=None):
__main__.MAIN.on_pot_stop_clicked()
__main__.MAIN.stop_ocp()
for i in self.buttons:
i.set_sensitive(False)
try:
self.builder.get_object('light_label').set_text(str(
dstat_comm.read_light_sensor()))
comm.read_settings()
state.settings['tcs_enabled'][1] = '1' # Make sure TCS enabled
comm.write_settings()
self.builder.get_object('threshold_entry').set_text(str(
state.settings['tcs_clear_threshold'][1]))
__main__.MAIN.start_ocp()
finally:
GObject.timeout_add(700, restore_buttons, self.buttons)
def on_threshold_button_clicked(self, data=None):
__main__.MAIN.on_pot_stop_clicked()
__main__.MAIN.stop_ocp()
for i in self.buttons:
i.set_sensitive(False)
try:
state.settings['tcs_clear_threshold'][1] = self.builder.get_object(
'threshold_entry').get_text()
comm.write_settings()
comm.read_settings()
self.builder.get_object('threshold_entry').set_text(
str(state.settings['tcs_clear_threshold'][1]))
__main__.MAIN.start_ocp()
finally:
GObject.timeout_add(700, restore_buttons, self.buttons)
def on_shutter_button_toggled(self, widget):
if self.bool['shutter_true'].get_active():
for i in self.shutter_buttons:
i.set_sensitive(True)
else:
for i in self.shutter_buttons:
i.set_sensitive(False)
class POT(ExpInterface):
"""Experiment class for Potentiometry."""
id = 'pot'
experiment = pot.PotExp
def __init__(self):
"""Adds entry listings to superclass's self.entry dict"""
super(POT, self).__init__(os.path.join(mod_dir, 'potexp.glade'))
self.name = "Potentiometry"
self.entry['time'] = self.builder.get_object('time_entry')
class CAL(ExpInterface):
"""Experiment class for Calibrating gain."""
id = 'cal'
experiment = cal.CALExp
def __init__(self):
"""Adds entry listings to superclass's self.entry dict"""
super(CAL, self).__init__(os.path.join(mod_dir, 'calib.glade'))
self.name = "Calilbration"
self.entry['time'] = self.builder.get_object('time_entry')
self.entry['R100'] = self.builder.get_object('100_entry')
self.entry['R3k'] = self.builder.get_object('3k_entry')
self.entry['R30k'] = self.builder.get_object('30k_entry')
self.entry['R300k'] = self.builder.get_object('300k_entry')
self.entry['R3M'] = self.builder.get_object('3M_entry')
self.entry['R30M'] = self.builder.get_object('30M_entry')
self.entry['R100M'] = self.builder.get_object('100M_entry')
self.buttons = [self.builder.get_object('read_button'),
self.builder.get_object('write_button'),
self.builder.get_object('measure_button')]
def on_read_button_clicked(self, data=None):
for i in self.buttons:
i.set_sensitive(False)
try:
__main__.MAIN.on_pot_stop_clicked()
__main__.MAIN.stop_ocp()
comm.read_settings()
self.entry['R100'].set_text(str(
state.settings['r100_trim'][1]))
self.entry['R3k'].set_text(str(
state.settings['r3k_trim'][1]))
self.entry['R30k'].set_text(str(
state.settings['r30k_trim'][1]))
self.entry['R300k'].set_text(str(
state.settings['r300k_trim'][1]))
self.entry['R3M'].set_text(str(
state.settings['r3M_trim'][1]))
self.entry['R30M'].set_text(str(
state.settings['r30M_trim'][1]))
self.entry['R100M'].set_text(str(
state.settings['r100M_trim'][1]))
__main__.MAIN.start_ocp()
finally:
GObject.timeout_add(700, restore_buttons, self.buttons)
def on_write_button_clicked(self, data=None):
for i in self.buttons:
i.set_sensitive(False)
try:
__main__.MAIN.on_pot_stop_clicked()
__main__.MAIN.stop_ocp()
state.settings['r100_trim'][1] = self.entry['R100'].get_text()
state.settings['r3k_trim'][1] = self.entry['R3k'].get_text()
state.settings['r30k_trim'][1] = self.entry['R30k'].get_text()
state.settings['r300k_trim'][1] = self.entry['R300k'].get_text()
state.settings['r3M_trim'][1] = self.entry['R3M'].get_text()
state.settings['r30M_trim'][1] = self.entry['R30M'].get_text()
state.settings['r100M_trim'][1] = self.entry['R100M'].get_text()
comm.write_settings()
__main__.MAIN.start_ocp()
finally:
GObject.timeout_add(700, restore_buttons, self.buttons)
def on_measure_button_clicked(self, data=None):
if int(self.entry['time'].get_text()) <= 0 or int(self.entry['time'].get_text()) > 65535:
logger.error("ERR: Time out of range")
return
for i in self.buttons:
i.set_sensitive(False)
try:
__main__.MAIN.stop_ocp()
__main__.MAIN.spinner.start()
offset = cal.measure_offset(self.params['time'])
for i in offset:
logger.info("{} {}".format(i, str(-offset[i])))
state.settings[i][1] = str(-offset[i])
self.entry['R100'].set_text(str(
state.settings['r100_trim'][1]))
self.entry['R3k'].set_text(str(
state.settings['r3k_trim'][1]))
self.entry['R30k'].set_text(str(
state.settings['r30k_trim'][1]))
self.entry['R300k'].set_text(str(
state.settings['r300k_trim'][1]))
self.entry['R3M'].set_text(str(
state.settings['r3M_trim'][1]))
self.entry['R30M'].set_text(str(
state.settings['r30M_trim'][1]))
self.entry['R100M'].set_text(str(
state.settings['r100M_trim'][1]))
__main__.MAIN.start_ocp()
finally:
GObject.timeout_add(700, restore_buttons, self.buttons)
__main__.MAIN.spinner.stop()
def restore_buttons(buttons):
""" Should be called with GObject callback """
for i in buttons:
i.set_sensitive(True)
return False
\ No newline at end of file
#!/usr/bin/env python
# DStat Interface - An interface for the open hardware DStat potentiostat
# Copyright (C) 2014 Michael D. M. Dryden -
# Wheeler Microfluidics Laboratory <http://microfluidics.utoronto.ca>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import inspect
import logging
from collections import OrderedDict
try:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
except ImportError:
print "ERR: GTK not available"
sys.exit(1)
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
self.builder.connect_signals(self)
# (experiment index in UI, experiment)
classes = {c.id : c() # Make class instances
for _, c in inspect.getmembers(exp_int, inspect.isclass)
if issubclass(c, exp_int.ExpInterface)
and c is not exp_int.ExpInterface
}
self.classes = OrderedDict(sorted(classes.items()))
# fill exp_section
exp_section = self.builder.get_object('exp_section_box')
self.containers = {}
for key, c in self.classes.items():
c.connect('run_utility', self.on_run_utility)
c.connect('done_utility', self.on_done_utility)
self.containers[key] = c.get_window()
for key in self.containers:
try:
self.containers[key].get_parent().remove(self.containers[key])
except AttributeError:
pass
exp_section.add(self.containers[key])
self.expcombobox = self.builder.get_object('expcombobox')
self.expcombobox.connect('changed', self.on_expcombobox_changed)
for c in self.classes.values():
self.expcombobox.append(id=c.id, text=c.name)
def on_run_utility(self, data=None):
self.emit('run_utility')
def on_done_utility(self, data=None):
self.emit('done_utility')
def on_expcombobox_changed(self, data=None):
"""Change the experiment window when experiment box changed."""
self.set_exp(self.expcombobox.get_active_id())
def setup_exp(self, parameters):
"""Takes parameters.
Returns experiment instance.
"""
exp = self.classes[self.expcombobox.get_active_id()]
try:
exp.param_test(parameters)
except AttributeError:
logger.warning(
"Experiment {} has no defined parameter test.".format(
exp.name)
)
return exp.get_experiment(parameters)
def hide_exps(self):
for key in self.containers:
self.containers[key].hide()
def set_exp(self, selection):
"""Changes parameter tab to selected experiment. Returns True if
successful, False if invalid selection received.
Arguments:
selection -- id string of experiment type
"""
self.hide_exps()
self.containers[selection].show()
self.selected_exp = selection
return True
def get_params(self, experiment):
return self.classes[experiment].params
def set_params(self, experiment, parameters):
try:
self.classes[experiment].params = parameters
except KeyError as e:
logger.warning("Tried to load inavlid experiment with id %s", e.args)
\ No newline at end of file
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from ..dstat import state, dfu
from ..dstat.comm import dstat_logger, exp_logger
import logging
import time
import serial
logger = logging.getLogger(__name__)
try:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
except ImportError:
print("ERR: GTK not available")
sys.exit(1)
class InfoDialog(object):
def __init__(self, parent, connect, signal='activate'):
self.parent = parent
connect.connect(signal, self.activate)
def activate(self, object=None, data=None):
self.dialog = Gtk.MessageDialog(self.parent, 0, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, "DStat Info")
self.dialog.format_secondary_text(
"PCB Version: {}\n".format(state.dstat_version.base_version) +
"Firmware Version: {}".format(state.firmware_version)
)
self.dialog.connect('response', self.destroy)
self.dialog.show()
def destroy(self, object=None, data=None):
self.dialog.destroy()
class ResetDialog(object):
def __init__(self, parent, connect, stop_callback, disconnect_callback, signal='activate'):
self.parent = parent
self.stop = stop_callback
self.disconnect = disconnect_callback
connect.connect(signal, self.activate)
def activate(self, object=None, data=None):
dialog = Gtk.MessageDialog(self.parent, 0, Gtk.MessageType.WARNING,
Gtk.ButtonsType.OK_CANCEL, "EEPROM Reset")
dialog.format_secondary_text("This will reset the DStat's EEPROM settings, then disconneect."
)
response = dialog.run()
if response == Gtk.ResponseType.OK:
self.dstat_reset_eeprom()
dialog.destroy()
def dstat_reset_eeprom(self):
"""Tries to contact DStat and resets EEPROM.
If no response, returns False, otherwise True.
"""
self.stop()
exp = EEPROMReset()
state.ser.start_exp(exp)
logger.info("Resetting DStat EEPROM…")
while True:
result = state.ser.get_proc(block=True)
if result in ('SERIAL_ERROR', 'DONE', 'ABORT'):
break
logger.info(result)
self.disconnect()
class EEPROMReset(object):
def __init__(self):
pass
def run(self, ser, ctrl_pipe, data_pipe):
status = None
try:
ser.write(b'!2\n')
exp_logger.info('!2')
for i in range(10):
if ser.readline().rstrip() == b"@ACK 2":
dstat_logger.info('@ACK 2')
ser.write(b'SD\n')
exp_logger.info('SD')
status = "DONE"
time.sleep(5)
break
else:
time.sleep(.5)
ser.reset_input_buffer()
ser.write(b'!2\n')
exp_logger.info('!2')
time.sleep(.1)
except UnboundLocalError as e:
status = "SERIAL_ERROR"
except serial.SerialException as e:
logger.error('SerialException: %s', e)
status = "SERIAL_ERROR"
finally:
return status
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Potential (mV)</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Time (s)</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Cleaning</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Deposition</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="clean_mV">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="dep_mV">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="dep_s">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="clean_s">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Preconditioning</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Start (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Stop (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Slope (mV/s)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="start_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="stop_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="slope_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Experiment</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkAdjustment" id="voltage_adjustment">
<property name="upper">3000</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkEntry" id="time_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Bias Voltage (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Measurement Time (s)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="invisible_char"></property>
<property name="text" translatable="yes">0</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="adjustment">voltage_adjustment</property>
<property name="climb_rate">1</property>
<property name="snap_to_ticks">True</property>
<property name="numeric">True</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Ambient Light Interlock</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="interlock_button">
<property name="label" translatable="yes">Enable interlock</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="threshold_button">
<property name="label" translatable="yes">Set threshold</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<signal name="clicked" handler="on_threshold_button_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="threshold_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="light_button">
<property name="label" translatable="yes">Refresh light measurement</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<signal name="clicked" handler="on_light_button_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="light_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">0</property>
<property name="justify">center</property>
<property name="track_visited_links">False</property>
<attributes>
<attribute name="weight" value="medium"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Electromechanical Shutter</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="sync_button">
<property name="label" translatable="yes">Synchronous Detection (Hz)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">center</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="sync_freq">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="shutter_button">
<property name="label" translatable="yes">Enable Shutter</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_shutter_button_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="fft_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Start FFT after (s)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="fft_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">2</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text">1</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="fft_label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">FFT Integral bandwidth (Hz)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="fft_int_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text">1</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
<property name="width">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
#!/usr/bin/env python
# DStat Interface - An interface for the open hardware DStat potentiostat
# Copyright (C) 2014 Michael D. M. Dryden -
# Wheeler Microfluidics Laboratory <http://microfluidics.utoronto.ca>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Creates data plot.
"""
try:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
except ImportError:
print "ERR: GTK not available"
sys.exit(1)
from matplotlib.figure import Figure
from matplotlib.backends.backend_gtk3agg \
import FigureCanvasGTK3Agg as FigureCanvas
from matplotlib.backends.backend_gtk3 \
import NavigationToolbar2GTK3 as NavigationToolbar
try:
import seaborn as sns
except ImportError:
pass
from numpy import sin, linspace, pi, mean, trapz
from scipy import fft, arange
def plotSpectrum(y,Fs):
"""
Plots a Single-Sided Amplitude Spectrum of y(t)
"""
y = y-mean(y)
n = len(y) # length of the signal
k = arange(n)
T = n/Fs
frq = k/T # two sides frequency range
frq = frq[range(n/2)] # one side frequency range
Y = fft(y)/n # fft computing and normalization
Y = abs(Y[range(n/2)])
return (frq, Y)
def integrateSpectrum(x, y, target, bandwidth):
"""
Returns integral of range of bandwidth centered on target (both in Hz).
"""
j = 0
k = len(x)
for i in range(len(x)):
if x[i] >= target-bandwidth/2:
j = i
break
for i in range(j,len(x)):
if x[i] >= target+bandwidth/2:
k = i
break
return trapz(y=y[j:k], x=x[j:k])
def findBounds(y):
start_index = 0;
stop_index = len(y)-1;
for i in range(len(y)):
if (y[i] <= mean(y) and y[i+1] > mean(y)):
start_index = i
break
for i in range(len(y)):
if (y[-(i+1)] <= mean(y) and y[-i] > mean(y)):
stop_index = len(y)-1-i # len(y) is last index + 1
break
return (start_index, stop_index)
import logging
logger = logging.getLogger(__name__)
try:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
except ImportError:
print "ERR: GTK not available"
sys.exit(1)
from matplotlib.backends.backend_gtk3 \
import NavigationToolbar2GTK3 as NavigationToolbar
def clear_notebook(notebook):
for pages in range(notebook.get_n_pages()):
notebook.remove_page(0)
def add_exp_to_notebook(notebook, exp):
for plot in exp.plots:
label = Gtk.Label.new(plot.name)
notebook.append_page(plot.box, label)
plot.box.show_all()
def replace_notebook_exp(notebook, exp, window):
clear_notebook(notebook)
add_exp_to_notebook(notebook, exp)
add_navigation_toolbars(exp, window)
def add_navigation_toolbars(exp, window):
for plot in exp.plots:
toolbar = NavigationToolbar(plot.canvas, window)
plot.box.pack_start(toolbar, expand=False, fill=False, padding=0)
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkListStore" id="ca_list">
<columns>
<!-- column-name millivolts -->
<column type="gint"/>
<!-- column-name seconds -->
<column type="guint"/>
</columns>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="default_width">300</property>
<property name="default_height">500</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Time (s)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="time_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">5</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="truncate_multiline">True</property>
<property name="caps_lock_warning">False</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Connect the electrodes to the RE input and the W_SHIELD connectors.
The ADC's PGA can be used to amplify the input signal, but note that the plot's y-axis is only correct for PGA 2x.</property>
<property name="wrap">True</property>
<property name="width_chars">30</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# DStat Interface - An interface for the open hardware DStat potentiostat
# Copyright (C) 2014 Michael D. M. Dryden -
# Wheeler Microfluidics Laboratory <http://microfluidics.utoronto.ca>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import division, absolute_import, print_function, unicode_literals
import io
import os
import logging
logger = logging.getLogger(__name__)
try:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
except ImportError:
print("ERR: GTK not available")
sys.exit(1)
import numpy as np
from ..errors import InputError, VarError
from ..params import save_params, load_params
def manSave(current_exp):
fcd = Gtk.FileChooserDialog("Save…", None, Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
filters = [Gtk.FileFilter()]
filters[0].set_name("Tab-separated Text (.txt)")
filters[0].add_pattern("*.txt")
fcd.set_do_overwrite_confirmation(True)
for i in filters:
fcd.add_filter(i)
response = fcd.run()
if response == Gtk.ResponseType.OK:
path = fcd.get_filename().decode("utf-8")
logger.info("Selected filepath: %s", path)
filter_selection = fcd.get_filter().get_name().decode("utf-8")
if filter_selection.endswith("(.txt)"):
save_text(current_exp, path)
fcd.destroy()
elif response == Gtk.ResponseType.CANCEL:
fcd.destroy()
def plot_save_dialog(plots):
fcd = Gtk.FileChooserDialog("Save Plot…", None,
Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
filters = [Gtk.FileFilter()]
filters[0].set_name("Portable Document Format (.pdf)")
filters[0].add_pattern("*.pdf")
filters.append(Gtk.FileFilter())
filters[1].set_name("Portable Network Graphics (.png)")
filters[1].add_pattern("*.png")
fcd.set_do_overwrite_confirmation(True)
for i in filters:
fcd.add_filter(i)
response = fcd.run()
if response == Gtk.ResponseType.OK:
path = fcd.get_filename().decode("utf-8")
logger.info("Selected filepath: %r", path)
filter_selection = fcd.get_filter().get_name().decode("utf-8")
if filter_selection.endswith("(.pdf)"):
if not path.endswith(".pdf"):
path += ".pdf"
elif filter_selection.endswith("(.png)"):
if not path.endswith(".png"):
path += ".png"
save_plot(plots, path)
fcd.destroy()
elif response == Gtk.ResponseType.CANCEL:
fcd.destroy()
def man_param_save(window):
fcd = Gtk.FileChooserDialog("Save Parameters…",
None,
Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
filters = [Gtk.FileFilter()]
filters[0].set_name("Parameter File (.yml)")
filters[0].add_pattern("*.yml")
fcd.set_do_overwrite_confirmation(True)
for i in filters:
fcd.add_filter(i)
response = fcd.run()
if response == Gtk.ResponseType.OK:
path = fcd.get_filename().decode("utf-8")
logger.info("Selected filepath: %s", path)
if not path.endswith(".yml"):
path += '.yml'
save_params(window, path)
fcd.destroy()
elif response == Gtk.ResponseType.CANCEL:
fcd.destroy()
def man_param_load(window):
fcd = Gtk.FileChooserDialog("Load Parameters…",
None,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
filters = [Gtk.FileFilter()]
filters[0].set_name("Parameter File (.yml)")
filters[0].add_pattern("*.yml")
for i in filters:
fcd.add_filter(i)
response = fcd.run()
if response == Gtk.ResponseType.OK:
path = fcd.get_filename().decode("utf-8")
logger.info("Selected filepath: %s", path)
load_params(window, path)
fcd.destroy()
elif response == Gtk.ResponseType.CANCEL:
fcd.destroy()
def autoSave(exp, path, name):
if name == "":
name = "file"
path += '/'
path += name
save_text(exp, path)
def autoPlot(exp, path, name):
if name == "":
name = "file"
path += '/'
path += name
if not (path.endswith(".pdf") or path.endswith(".png")):
path += ".pdf"
save_plot(exp, path)
def save_text(exp, path):
savestrings = exp.get_save_strings()
path = path.rstrip('.txt')
num = ''
j = 0
for key, text in savestrings.items(): # Test for existing files of any kind
while os.path.exists("{}{}-{}.txt".format(path, num, key)):
j += 1
num = j
save_path = "{}{}".format(path, num)
for key, text in savestrings.items():
with open('{}-{}.txt'.format(save_path, key), 'w') as f:
f.write(text)
def save_plot(exp, path):
"""Saves everything in exp.plots to path. Appends a number for duplicates.
If no file extension or unknown, uses pdf.
"""
name, _sep, ext = path.rpartition('.')
if _sep == '':
name = ext
ext = 'pdf'
num = ''
j = 0
for i in exp.plots: # Test for any existing files
plot_type = '_'.join(i.name.lower().split())
while os.path.exists("{}{}-{}.{}".format(name, num, plot_type, ext)):
j += 1
num = j
for i in exp.plots: # save data
plot_type = '_'.join(i.name.lower().split())
i.figure.savefig("{}{}-{}.{}".format(name, num, plot_type, ext))
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkFrame" id="frame1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Potential (mV)</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Time (s)</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Cleaning</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Deposition</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="clean_mV">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="dep_mV">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="dep_s">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="clean_s">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Preconditioning</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="bottom_padding">5</property>
<property name="left_padding">5</property>
<property name="right_padding">5</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkEntry" id="scans_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="cyclic_checkbutton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="use_stock">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Scans</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Scan both forwards and backwards.</property>
<property name="label" translatable="yes">Cyclic Mode</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="freq_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="pulse_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Frequency (Hz)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Pulse Height (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="step_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="stop_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="start_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
<property name="xalign">1</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Step Size (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Stop (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Start (mV)</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Experiment</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Note: ADC samples 1/(ADC Frequency) before end of pulse. ADC frequency should be significantly larger than SWV frequency to reduce capacitive current.</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<property name="width_chars">43</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
#!/usr/bin/env python
# DStat Interface - An interface for the open hardware DStat potentiostat
# Copyright (C) 2014 Michael D. M. Dryden -
# Wheeler Microfluidics Laboratory <http://microfluidics.utoronto.ca>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import zmq
#signals
CONREQ = "0"
CONREP = "1"
STARTEXP = "start"
START_REP = "started"
EXP_FINISH_REQ = "notify_completion"
EXPFINISHED = "completed"
INVAL_CMD = "99"
#States
RECV = 0
SEND = 1
class microdropConnection(object):
"""Manages microdrop connection over TCP with zmq"""
def __init__(self, port=6789):
"""Create zmq context and bind to port. Should be called manually
to reinitialize if reset is called.
Keyword arguments:
port -- the TCP to bind to on localhost
"""
self.port = port
self.connected = False
self.state = RECV
self.ctx = zmq.Context()
self.soc = zmq.Socket(self.ctx, zmq.REP)
self.soc.bind("".join(['tcp://*:', str(self.port)]))
def listen(self):
"""Perform non-blocking recv on zmq port. self.state must be RECV.
Returns a tuple:
[0] -- True if a message was received, False otherwise.
[1] -- The recieved message or "" if no message received.
"""
if self.state == SEND:
print "WAR: [uDrop-listen] Connection state invalid, resetting..."
# self.reset()
# self.__init__(self.port)
return (False, "")
try:
message = self.soc.recv(flags=zmq.NOBLOCK, copy=True)
self.state = SEND
return (True, message)
except zmq.Again:
return (False, "")
def reply(self, data):
"""Sends a reply on zmq port. self.state must be SEND.
Arguments:
data -- a str to be sent
"""
if self.state == RECV:
print "WAR: [uDrop-reply] Connection state invalid, resetting..."
self.reset()
self.__init__(self.port)
return False
self.state = RECV
self.soc.send(data)
return True
def reset(self):
"""Reset zmq interface. Must call __init__ again to reinitialize."""
self.soc.unbind("".join(['tcp://*:', str(self.port)]))
del self.soc
del self.ctx
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# DStat Interface - An interface for the open hardware DStat potentiostat
# Copyright (C) 2014 Michael D. M. Dryden -
# Wheeler Microfluidics Laboratory <http://microfluidics.utoronto.ca>
#
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import yaml
from errors import InputError
logger = logging.getLogger(__name__)
def get_params(window):
"""Fetches and returns dict of all parameters for saving."""
selection = window.exp_window.expcombobox.get_active_id()
parameters = {'experiment_index' : selection}
try:
parameters['version'] = window.version
except AttributeError: # Will be thrown if not connected to DStat
pass
try:
parameters.update(window.adc_pot.params)
except InputError:
logger.info("No gain selected.")
parameters.update(window.exp_window.get_params(selection))
parameters.update(window.analysis_opt_window.params)
return parameters
def save_params(window, path):
"""Fetches current params and saves to path."""
logger.info("Save to: %s", path)
params = get_params(window)
with open(path, 'w') as f:
yaml.dump(params, f)
def load_params(window, path):
"""Loads params from a path into UI elements."""
try:
get_params(window)
except InputError: # Will be thrown because no experiment will be selected
pass
except KeyError: # Will be thrown because no experiment will be selected
pass
with open(path, 'r') as f:
params = yaml.load(f)
set_params(window, params)
def set_params(window, params):
window.adc_pot.params = params
if 'experiment_index' in params:
window.exp_window.expcombobox.set_active_id(params['experiment_index'])
window.exp_window.set_params(params['experiment_index'], params)
window.analysis_opt_window.params = params
window.params_loaded = True
# -*- coding: utf-8 -*-
import logging
from params import get_params, set_params, load_params, save_params
from interface.save import save_text, save_plot
from zmq_plugin.plugin import Plugin as ZmqPlugin
from zmq_plugin.schema import decode_content_data
import gtk
import zmq
logger = logging.getLogger(__name__)
def get_hub_uri(default='tcp://localhost:31000', parent=None):
message = 'Please enter 0MQ hub URI:'
d = gtk.MessageDialog(parent=parent, flags=gtk.DIALOG_MODAL |
gtk.DIALOG_DESTROY_WITH_PARENT,
type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK_CANCEL,
message_format=message)
entry = gtk.Entry()
entry.set_text(default)
d.vbox.pack_end(entry)
d.vbox.show_all()
entry.connect('activate', lambda _: d.response(gtk.RESPONSE_OK))
d.set_default_response(gtk.RESPONSE_OK)
r = d.run()
text = entry.get_text().decode('utf8')
d.destroy()
if r == gtk.RESPONSE_OK:
return text
else:
return None
class DstatPlugin(ZmqPlugin):
'''
Public 0MQ plugin API.
'''
def __init__(self, parent, *args, **kwargs):
self.parent = parent
super(DstatPlugin, self).__init__(*args, **kwargs)
def check_sockets(self):
'''
Check for messages on command and subscription sockets and process
any messages accordingly.
'''
try:
msg_frames = self.command_socket.recv_multipart(zmq.NOBLOCK)
except zmq.Again:
pass
else:
self.on_command_recv(msg_frames)
try:
msg_frames = self.subscribe_socket.recv_multipart(zmq.NOBLOCK)
source, target, msg_type, msg_json = msg_frames
self.most_recent = msg_json
except zmq.Again:
pass
except:
logger.error('Error processing message from subscription '
'socket.', exc_info=True)
return True
def on_execute__load_params(self, request):
'''
Args
----
params_path (str) : Path to file for parameters yaml file.
'''
data = decode_content_data(request)
load_params(self.parent, data['params_path'])
def on_execute__save_params(self, request):
'''
Args
----
params_path (str) : Path to file for parameters yaml file.
'''
data = decode_content_data(request)
save_params(self.parent, data['params_path'])
def on_execute__set_params(self, request):
'''
Args
----
(dict) : Parameters dictionary in format returned by `get_params`.
'''
data = decode_content_data(request)
set_params(self.parent, data['params'])
def on_execute__get_params(self, request):
return get_params(self.parent)
def on_execute__run_active_experiment(self, request):
data = decode_content_data(request)
self.parent.statusbar.push(self.parent.message_context_id, "µDrop "
"acquisition requested.")
return self.parent.run_active_experiment(
param_override=data.get('params'),
metadata=data.get('metadata')
)
def on_execute__set_metadata(self, request=None):
'''
Args
----
(dict) : Dictionary of metadata to be used in subsequent
experiments. Should include `device_id`, `patient_id`, and
`experiment_id`. Leave blank to reset all metadata fields or set
individual keys to `None` to reset individual values.
'''
data = decode_content_data(request)
self.parent.metadata = request
def on_execute__save_text(self, request):
'''
Args
----
save_data_path (str) : Path to file to save text data.
'''
data = decode_content_data(request)
save_text(self.parent.current_exp, data['save_data_path'])
def on_execute__save_plot(self, request):
'''
Args
----
save_plot_path (str) : Path to file to save plot.
'''
data = decode_content_data(request)
save_plot(self.parent.current_exp, data['save_plot_path'])
def on_execute__acquisition_complete(self, request):
'''
Args
----
Returns
-------
(datetime.datetime or None) : The completion time of the experiment
corresponding to the specified UUID.
'''
data = decode_content_data(request)
self.parent.statusbar.push(self.parent.message_context_id, "µDrop "
"notified of completed acquisition.")
if data['experiment_id'] in self.parent.completed_experiment_ids:
return self.parent.completed_experiment_ids[data['experiment_id']]
elif data['experiment_id'] == self.parent.active_experiment_id:
return None
else:
raise KeyError('Unknown experiment ID: %s' % data['experiment_id'])
from datetime import datetime
import os
from pathlib import Path
from appdirs import AppDirs
app_dirs = AppDirs("dstat-interface", "Wheeler Lab")
experiment_name = 'experiment_{}'.format(datetime.now().strftime('%y-%m-%d_%H.%M.%S'))
experiment_folder_location: Path = Path(app_dirs.user_data_dir) / 'Experiments' / experiment_name
from abc import ABCMeta, abstractmethod
import trio
from dstat_interface.core.experiments.experiment_container import ExperimentContainer
class BaseTasks(object, metaclass=ABCMeta):
def __init__(self):
self.tasks = []
async def loop(self):
async with trio.open_nursery() as nursery:
for task in self.tasks:
nursery.start_soon(task, nursery.cancel_scope)
class ExperimentBaseTasks(BaseTasks):
def __init__(self, exp_con: ExperimentContainer):
super().__init__()
self.exp_con = exp_con
self.tasks += [self.update_progress, self.exp_runner]
@abstractmethod
async def update_progress(self, cancel_scope: trio.CancelScope):
pass
async def exp_runner(self, cancel_scope: trio.CancelScope):
while True:
if not self.exp_con.handler_instance.experiment_running_data():
return
if not self.exp_con.handler_instance.experiment_running_proc():
self.exp_con.handler_instance.get_all_data()
return
await trio.sleep(0)
# -*- coding: utf-8 -*-
"""Calculates the current version number.
If possible, uses output of “git describe” modified to conform to the
visioning scheme that setuptools uses (see PEP 386). Releases must be
labelled with annotated tags (signed tags are annotated) of the following
format:
v<num>(.<num>)+ [ {a|b|c|rc} <num> (.<num>)* ]
If “git describe” returns an error (likely because we're in an unpacked copy
of a release tarball, rather than a git working copy), or returns a tag that
does not match the above format, version is read from RELEASE-VERSION file.
To use this script, simply import it your setup.py file, and use the results
of getVersion() as your package version:
import version
setup(
version=version.getVersion(),
.
.
.
)
This will automatically update the RELEASE-VERSION file. The RELEASE-VERSION
file should *not* be checked into git but it *should* be included in sdist
tarballs (as should version.py file). To do this, run:
echo include RELEASE-VERSION version.py >>MANIFEST.in
echo RELEASE-VERSION >>.gitignore
With that setup, a new release can be labelled by simply invoking:
git tag -s v1.0
"""
__author__ = ('Douglas Creager <dcreager@dcreager.net>',
'Michal Nazarewicz <mina86@mina86.com>')
__license__ = 'This file is placed into the public domain.'
__maintainer__ = 'Michal Nazarewicz'
__email__ = 'mina86@mina86.com'
__all__ = ('getVersion')
import re
import subprocess
import sys
import os.path
import inspect
RELEASE_VERSION_FILE = '{}/RELEASE-VERSION'.format(
os.path.dirname(os.path.abspath(inspect.stack()[0][1])))
# http://www.python.org/dev/peps/pep-0386/
_PEP386_SHORT_VERSION_RE = r'\d+(?:\.\d+)+(?:(?:[abc]|rc)\d+(?:\.\d+)*)?'
_PEP386_VERSION_RE = r'^%s(?:\.post\d+)?(?:\.dev\d+)?$' % (
_PEP386_SHORT_VERSION_RE)
_GIT_DESCRIPTION_RE = r'^v(?P<ver>%s)-(?P<commits>\d+)-g(?P<sha>[\da-f]+)$' % (
_PEP386_SHORT_VERSION_RE)
def readGitVersion():
try:
proc = subprocess.Popen(('git', 'describe', '--long',
'--match', 'v[0-9]*.*'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
data, _ = proc.communicate()
if proc.returncode:
return None
ver = data.splitlines()[0].strip()
proc = subprocess.Popen(('git', 'rev-parse', '--abbrev-ref', 'HEAD'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
branch, _ = proc.communicate()
if proc.returncode:
return None
except:
return None
if not ver:
return None
m = re.search(_GIT_DESCRIPTION_RE, ver)
if not m:
sys.stderr.write('version: git description (%s) is invalid, '
'ignoring\n' % ver)
return None
commits = int(m.group('commits'))
if not commits:
version = m.group('ver')
else:
version = '%s.post%d' % (
m.group('ver'), commits)
if branch.strip() != 'master':
version += '.dev%d' % int(m.group('sha'), 16)
return version
def readReleaseVersion():
try:
fd = open(RELEASE_VERSION_FILE)
try:
ver = fd.readline().strip()
finally:
fd.close()
if not re.search(_PEP386_VERSION_RE, ver):
sys.stderr.write('version: release version (%s) is invalid, '
'will use it anyway\n' % ver)
return ver
except:
return None
def writeReleaseVersion(version):
fd = open(RELEASE_VERSION_FILE, 'w')
fd.write('%s\n' % version)
fd.close()
def getVersion():
release_version = readReleaseVersion()
version = readGitVersion() or release_version
if not version:
raise ValueError('Cannot find the version number')
if version != release_version:
writeReleaseVersion(version)
return version
if __name__ == '__main__':
print getVersion()