Skip to content
Snippets Groups Projects
Commit 6fae1d39 authored by Michael DM Dryden's avatar Michael DM Dryden
Browse files

Automatic offset calibration.

parent 7ef67f41
Branches
No related merge requests found
python .\__main__.py
python .\main.py
......@@ -79,19 +79,6 @@ class SerialConnection(object):
self.proc.start()
def call_it(instance, name, args=(), kwargs=None):
"""Indirect caller for instance methods and multiprocessing.
Arguments:
instance -- instance to which the method belongs
name -- method to call
args -- passed to method
kwargs -- passed to method
"""
if kwargs is None:
kwargs = {}
return getattr(instance, name)(*args, **kwargs)
class VersionCheck:
def __init__(self):
pass
......@@ -131,7 +118,31 @@ class VersionCheck:
finally:
return status
def version_check(ser_port):
"""Tries to contact DStat and get version. Returns a list of
[(major, minor), serial instance]. If no response, returns empty tuple.
Arguments:
ser_port -- address of serial port to use
"""
try:
global serial_instance
serial_instance = SerialConnection(ser_port)
serial_instance.proc_pipe_p.send(VersionCheck())
result = serial_instance.proc_pipe_p.recv()
if result == "SERIAL_ERROR":
buffer = 1
else:
buffer = serial_instance.data_pipe_p.recv()
print result
return buffer
except:
pass
class Settings:
def __init__(self, task, settings=None):
self.task = task
......@@ -201,7 +212,39 @@ class Settings:
self.ser.write(' ')
return
def read_settings():
"""Tries to contact DStat and get settings. Returns dict of
settings.
"""
global settings
settings = {}
while serial_instance.data_pipe_p.poll():
serial_instance.data_pipe_p.recv()
serial_instance.proc_pipe_p.send(Settings(task='r'))
settings = serial_instance.data_pipe_p.recv()
print serial_instance.proc_pipe_p.recv()
return
def write_settings():
"""Tries to write settings to DStat from global settings var.
"""
while serial_instance.data_pipe_p.poll():
serial_instance.data_pipe_p.recv()
serial_instance.proc_pipe_p.send(Settings(task='w', settings=settings))
while serial_instance.proc_pipe_p.recv() != "DONE":
pass
return
class LightSensor:
def __init__(self):
pass
......@@ -238,37 +281,14 @@ class LightSensor:
return status
def version_check(ser_port):
"""Tries to contact DStat and get version. Returns a list of
[(major, minor), serial instance]. If no response, returns empty tuple.
Arguments:
ser_port -- address of serial port to use
"""
try:
global serial_instance
serial_instance = SerialConnection(ser_port)
serial_instance.proc_pipe_p.send(VersionCheck())
result = serial_instance.proc_pipe_p.recv()
if result == "SERIAL_ERROR":
buffer = 1
else:
buffer = serial_instance.data_pipe_p.recv()
print result
return buffer
except:
pass
def read_light_sensor():
"""Tries to contact DStat and get light sensor reading. Returns uint of
light sensor clear channel.
"""
while serial_instance.data_pipe_p.poll():
serial_instance.data_pipe_p.recv()
serial_instance.proc_pipe_p.send(LightSensor())
while serial_instance.proc_pipe_p.recv() != "DONE":
......@@ -276,32 +296,6 @@ def read_light_sensor():
return serial_instance.data_pipe_p.recv()
def read_settings():
"""Tries to contact DStat and get settings. Returns dict of
settings.
"""
global settings
settings = {}
serial_instance.proc_pipe_p.send(Settings(task='r'))
settings = serial_instance.data_pipe_p.recv()
while serial_instance.proc_pipe_p.recv() != "DONE":
pass
return
def write_settings():
"""Tries to write settings to DStat from global settings var.
"""
serial_instance.proc_pipe_p.send(Settings(task='w'))
while serial_instance.proc_pipe_p.recv() != "DONE":
pass
return
class delayedSerial(serial.Serial):
"""Extends Serial.write so that characters are output individually
......@@ -329,12 +323,6 @@ class Experiment(object):
"""Store and acquire a potentiostat experiment. Meant to be subclassed
to by different experiment types and not used instanced directly.
"""
# def run_wrapper(self, *argv):
# """Execute experiment indirectly using call_it to bypass lack of fork()
# on Windows for multiprocessing.
# """
# self.proc = mp.Process(target=call_it, args=(self, 'run', argv))
# self.proc.start()
def __init__(self, parameters):
"""Adds commands for gain and ADC."""
......@@ -399,16 +387,14 @@ class Experiment(object):
self.serial.write(i)
if not self.serial_handler():
status = "ABORT"
break
self.data_postprocessing()
except serial.SerialException:
status = "SERIAL_ERROR"
finally:
self.data_postprocessing()
while self.ctrl_pipe.poll():
self.ctrl_pipe.recv()
return status
return status
def serial_handler(self):
"""Handles incoming serial transmissions from DStat. Returns False
......@@ -468,6 +454,91 @@ class Experiment(object):
"""
pass
class CALExp(Experiment):
"""Offset calibration experiment"""
def __init__(self, parameters):
self.parameters = parameters
self.databytes = 8
self.scan = 0
self.data = []
self.commands = ["EA2 3 1 ", "EG", "ER"]
self.commands[1] += str(self.parameters['gain'])
self.commands[1] += " "
self.commands[1] += "0 "
self.commands[2] += "1 32768 "
self.commands[2] += str(self.parameters['time'])
self.commands[2] += " "
self.commands[2] += "0 " # disable photodiode interlock
def serial_handler(self):
"""Handles incoming serial transmissions from DStat. Returns False
if stop button pressed and sends abort signal to instrument. Sends
data to self.data_pipe as result of self.data_handler).
"""
try:
while True:
if self.ctrl_pipe.poll():
print "serial_handler ctrl_pipe"
input = self.ctrl_pipe.recv()
print input
if input == ('a' or "DISCONNECT"):
self.serial.write('a')
print "ABORT pressed!"
return False
for line in self.serial:
if self.ctrl_pipe.poll():
if self.ctrl_pipe.recv() == 'a':
self.serial.write('a')
print "ABORT pressed"
return False
if line.startswith('B'):
self.data.append(self.data_handler(
self.serial.read(size=self.databytes)))
elif line.lstrip().startswith("#"):
print line
elif line.lstrip().startswith("no"):
print line
self.serial.flushInput()
return True
except serial.SerialException:
return False
def data_handler(self, data):
"""Takes data_input as tuple -- (scan, data).
Returns:
current
"""
seconds, milliseconds, current = struct.unpack('<HHl', data)
return current
def data_postprocessing(self):
"""Averages data points
"""
sum = 0
self.data[0] = 0 # Skip first point
for i in self.data:
sum += i
sum /= len(self.data)
if (sum > 32767):
sum = 32767
elif (sum < -32768):
sum = -32768
self.data_pipe.send(sum)
class Chronoamp(Experiment):
"""Chronoamperometry experiment"""
def __init__(self, parameters):
......@@ -754,4 +825,21 @@ class OCPExp(Experiment):
scan, data = data_input
# 2*uint16 + int32
seconds, milliseconds, voltage = struct.unpack('<HHl', data)
return (voltage/5.592405e6)
\ No newline at end of file
return (voltage/5.592405e6)
def measure_offset(time):
gain_trim_table = [None, 'r100_trim', 'r3k_trim', 'r30k_trim', 'r300k_trim',
'r3M_trim', 'r30M_trim', 'r100M_trim']
parameters = {}
parameters['time'] = time
gain_offset = {}
for i in range(1,8):
parameters['gain'] = i
serial_instance.proc_pipe_p.send(CALExp(parameters))
print serial_instance.proc_pipe_p.recv()
gain_offset[gain_trim_table[i]] = serial_instance.data_pipe_p.recv()
return gain_offset
\ No newline at end of file
......@@ -26,10 +26,20 @@
<property name="n_rows">13</property>
<property name="n_columns">2</property>
<property name="homogeneous">True</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkEntry" id="time_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">5</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -55,6 +65,7 @@
<property name="label" translatable="yes">Measurement Time (s)</property>
</object>
<packing>
<property name="x_options"/>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
......@@ -78,6 +89,8 @@
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options"/>
<property name="x_padding">10</property>
</packing>
</child>
<child>
......@@ -102,6 +115,7 @@
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options"/>
</packing>
</child>
<child>
......@@ -113,6 +127,7 @@
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
<child>
......@@ -124,6 +139,7 @@
<packing>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
<child>
......@@ -135,6 +151,7 @@
<packing>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
<child>
......@@ -146,6 +163,7 @@
<packing>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
<child>
......@@ -157,6 +175,7 @@
<packing>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
<child>
......@@ -168,13 +187,14 @@
<packing>
<property name="top_attach">9</property>
<property name="bottom_attach">10</property>
<property name="x_options">GTK_EXPAND</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="30k_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -199,7 +219,7 @@
<object class="GtkEntry" id="3k_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -224,7 +244,7 @@
<object class="GtkEntry" id="100_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -249,7 +269,7 @@
<object class="GtkEntry" id="300k_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -274,7 +294,7 @@
<object class="GtkEntry" id="3M_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -299,7 +319,7 @@
<object class="GtkEntry" id="30M_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -324,7 +344,7 @@
<object class="GtkEntry" id="100M_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">4</property>
<property name="max_length">6</property>
<property name="invisible_char"></property>
<property name="width_chars">8</property>
<property name="text" translatable="yes">0</property>
......@@ -385,6 +405,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_measure_button_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
......@@ -395,15 +416,6 @@
<property name="y_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
......@@ -415,9 +427,10 @@
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xpad">20</property>
<property name="xpad">5</property>
<property name="ypad">20</property>
<property name="label" translatable="yes">Measure with WE open. Offsets cannot exceed 16 bit unsigned int.</property>
<property name="label" translatable="yes">Measure with WE open.
Offsets cannot exceed 16 bit unsigned int.</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
......
......@@ -262,40 +262,100 @@ class CAL(ExpInterface):
self.entry['R30M'] = self.builder.get_object('30M_entry')
self.entry['R100M'] = self.builder.get_object('100M_entry')
def on_read_button_clicked(self, data=None):
__main__.MAIN.on_pot_stop_clicked()
self.buttons = [self.builder.get_object('read_button'),
self.builder.get_object('write_button'),
self.builder.get_object('measure_button')]
gobject.source_remove(__main__.MAIN.ocp_proc)
dstat_comm.read_settings()
self.entry['R100'].set_text(str(
dstat_comm.settings['r100_trim'][1]))
self.entry['R3k'].set_text(str(
dstat_comm.settings['r3k_trim'][1]))
self.entry['R30k'].set_text(str(
dstat_comm.settings['r30k_trim'][1]))
self.entry['R300k'].set_text(str(
dstat_comm.settings['r300k_trim'][1]))
self.entry['R3M'].set_text(str(
dstat_comm.settings['r3M_trim'][1]))
self.entry['R30M'].set_text(str(
dstat_comm.settings['r30M_trim'][1]))
self.entry['R100M'].set_text(str(
dstat_comm.settings['r100M_trim'][1]))
__main__.MAIN.start_ocp()
def on_read_button_clicked(self, data=None):
for i in self.buttons:
i.set_sensitive(False)
try:
__main__.MAIN.on_pot_stop_clicked()
gobject.source_remove(__main__.MAIN.ocp_proc)
dstat_comm.read_settings()
self.entry['R100'].set_text(str(
dstat_comm.settings['r100_trim'][1]))
self.entry['R3k'].set_text(str(
dstat_comm.settings['r3k_trim'][1]))
self.entry['R30k'].set_text(str(
dstat_comm.settings['r30k_trim'][1]))
self.entry['R300k'].set_text(str(
dstat_comm.settings['r300k_trim'][1]))
self.entry['R3M'].set_text(str(
dstat_comm.settings['r3M_trim'][1]))
self.entry['R30M'].set_text(str(
dstat_comm.settings['r30M_trim'][1]))
self.entry['R100M'].set_text(str(
dstat_comm.settings['r100M_trim'][1]))
__main__.MAIN.start_ocp()
finally:
for i in self.buttons:
i.set_sensitive(True)
def on_write_button_clicked(self, data=None):
__main__.MAIN.on_pot_stop_clicked()
gobject.source_remove(__main__.MAIN.ocp_proc)
for i in self.buttons:
i.set_sensitive(False)
try:
__main__.MAIN.on_pot_stop_clicked()
gobject.source_remove(__main__.MAIN.ocp_proc)
dstat_comm.settings['r100_trim'][1] = self.entry['R100'].get_text()
dstat_comm.settings['r3k_trim'][1] = self.entry['R3k'].get_text()
dstat_comm.settings['r30k_trim'][1] = self.entry['R30k'].get_text()
dstat_comm.settings['r300k_trim'][1] = self.entry['R300k'].get_text()
dstat_comm.settings['r3M_trim'][1] = self.entry['R3M'].get_text()
dstat_comm.settings['r30M_trim'][1] = self.entry['R30M'].get_text()
dstat_comm.settings['r100M_trim'][1] = self.entry['R100M'].get_text()
dstat_comm.write_settings()
__main__.MAIN.start_ocp()
finally:
for i in self.buttons:
i.set_sensitive(True)
def on_measure_button_clicked(self, data=None):
if (int(self.entry['time'].get_text()) <= 0 or int(self.entry['time'].get_text()) > 65535):
print "ERR: Time out of range"
return
for i in self.buttons:
i.set_sensitive(False)
try:
__main__.MAIN.on_pot_stop_clicked()
gobject.source_remove(__main__.MAIN.ocp_proc)
__main__.MAIN.spinner.start()
offset = dstat_comm.measure_offset(self.get_params()['time'])
for i in offset:
print i
print str(-offset[i])
dstat_comm.settings[i][1] = str(-offset[i])
self.entry['R100'].set_text(str(
dstat_comm.settings['r100_trim'][1]))
self.entry['R3k'].set_text(str(
dstat_comm.settings['r3k_trim'][1]))
self.entry['R30k'].set_text(str(
dstat_comm.settings['r30k_trim'][1]))
self.entry['R300k'].set_text(str(
dstat_comm.settings['r300k_trim'][1]))
self.entry['R3M'].set_text(str(
dstat_comm.settings['r3M_trim'][1]))
self.entry['R30M'].set_text(str(
dstat_comm.settings['r30M_trim'][1]))
self.entry['R100M'].set_text(str(
dstat_comm.settings['r100M_trim'][1]))
__main__.MAIN.start_ocp()
dstat_comm.settings['r100_trim'][1] = self.entry['R100'].get_text()
dstat_comm.settings['r3k_trim'][1] = self.entry['R3k'].get_text()
dstat_comm.settings['r30k_trim'][1] = self.entry['R30k'].get_text()
dstat_comm.settings['r300k_trim'][1] = self.entry['R300k'].get_text()
dstat_comm.settings['r3M_trim'][1] = self.entry['R3M'].get_text()
dstat_comm.settings['r30M_trim'][1] = self.entry['R30M'].get_text()
dstat_comm.settings['r100M_trim'][1] = self.entry['R100M'].get_text()
dstat_comm.write_settings()
__main__.MAIN.start_ocp()
\ No newline at end of file
finally:
for i in self.buttons:
i.set_sensitive(True)
__main__.MAIN.spinner.stop()
\ No newline at end of file
......@@ -731,6 +731,8 @@ class Main(object):
for i in self.current_exp.commands:
self.rawbuffer.insert_at_cursor(i)
self.rawbuffer.insert_at_cursor("\n")
for col in zip(*self.current_exp.data):
for row in col:
self.rawbuffer.insert_at_cursor(str(row)+ " ")
......@@ -769,6 +771,9 @@ class Main(object):
comm.serial_instance.ctrl_pipe_p.send('a')
while not (comm.serial_instance.proc_pipe_p.recv() == "ABORT"):
pass
while comm.serial_instance.data_pipe_p.poll():
comm.serial_instance.data_pipe_p.recv()
except AttributeError:
pass
except:
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment