From d845b129f0a2e28119f2c4fe247ef906f6efff7f Mon Sep 17 00:00:00 2001
From: "Michael D. M. Dryden" <mdryden@chem.utoronto.ca>
Date: Tue, 17 Nov 2015 16:30:33 -0500
Subject: [PATCH] Support new hierarchical command protocol. Implements #7

---
 dstat-interface/dstat_comm.py      |  68 +++++++++------
 dstat-interface/interface/pd.glade | 129 +++++++++++++++++++++++++++--
 dstat-interface/main.py            |   8 +-
 3 files changed, 171 insertions(+), 34 deletions(-)

diff --git a/dstat-interface/dstat_comm.py b/dstat-interface/dstat_comm.py
index ebd496c..64dfba1 100644
--- a/dstat-interface/dstat_comm.py
+++ b/dstat-interface/dstat_comm.py
@@ -128,7 +128,7 @@ class Experiment(object):
             
         self.gain = self.__gaintable[int(self.parameters['gain'])]
 
-        self.commands = ["A", "G"]
+        self.commands = ["EA", "EG"]
     
         self.commands[0] += (self.parameters['adc_buffer'])
         self.commands[0] += " "
@@ -148,23 +148,29 @@ class Experiment(object):
         ser -- serial instance to use
         """
         self.serial = ser
-        self.serial.write("ck")
-        self.serial.flushInput()
+#         self.serial.write("ck")
         
-        for i in self.commands:
-            print i
-            self.serial.write('!')
+        try:
+            self.serial.flushInput()
             
-            while not self.serial.read().startswith("C"):
-                pass
-
-            self.serial.write(i)
-            if not self.serial_handler():
-                self.main_pipe.send("ABORT")
-                break
-
-        self.data_postprocessing()
-        self.main_pipe.close()
+            for i in self.commands:
+                print i
+                self.serial.write('!')
+                
+                while not self.serial.read().startswith("C"):
+                    pass
+    
+                self.serial.write(i)
+                if not self.serial_handler():
+                    self.main_pipe.send("ABORT")
+                    break
+                    
+        except serial.SerialException:
+            self.main_pipe.send("ABORT")
+            
+        finally:
+            self.data_postprocessing()
+            self.main_pipe.close()
     
     def serial_handler(self):
         """Handles incoming serial transmissions from DStat. Returns False
@@ -198,6 +204,7 @@ class Experiment(object):
                         print line
                         self.serial.flushInput()
                         return True
+                        
         except serial.SerialException:
             return False
     
@@ -235,7 +242,8 @@ class Chronoamp(Experiment):
         for i in self.parameters['time']:
             self.xmax += int(i)
         
-        self.commands += "R"
+        self.commands += "E"
+        self.commands[2] += "R"
         self.commands[2] += str(len(self.parameters['potential']))
         self.commands[2] += " "
         for i in self.parameters['potential']:
@@ -244,6 +252,7 @@ class Chronoamp(Experiment):
         for i in self.parameters['time']:
             self.commands[2] += str(i)
             self.commands[2] += " "
+        self.commands[2] += "0 " # disable photodiode interlock
             
     def data_handler(self, data_input):
         """Overrides Experiment method to not convert x axis to mV."""
@@ -267,7 +276,8 @@ class PDExp(Chronoamp):
         self.xmin = 0
         self.xmax = self.parameters['time']
         
-        self.commands += "R"
+        self.commands += "E"
+        self.commands[2] += "R"
         self.commands[2] += "1"
         self.commands[2] += " "
         
@@ -279,6 +289,11 @@ class PDExp(Chronoamp):
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['time'])
         self.commands[2] += " "
+        if self.parameters['interlock']:
+            self.commands[2] += "1"
+        else:
+            self.commands[2] += "0"
+        self.commands[2] += " "
 
 class PotExp(Experiment):
     """Potentiometry experiment"""
@@ -294,7 +309,8 @@ class PotExp(Experiment):
         self.xmin = 0
         self.xmax = self.parameters['time']
         
-        self.commands += "P"
+        self.commands += "E"
+        self.commands[2] += "P"
         self.commands[2] += str(self.parameters['time'])
         self.commands[2] += " 1 " #potentiometry mode
 
@@ -320,7 +336,8 @@ class LSVExp(Experiment):
         self.xmin = self.parameters['start']
         self.xmax = self.parameters['stop']
         
-        self.commands += "L"
+        self.commands += "E"
+        self.commands[2] += "L"
         self.commands[2] += str(self.parameters['clean_s'])
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
@@ -352,7 +369,8 @@ class CVExp(Experiment):
         self.xmin = self.parameters['v1']
         self.xmax = self.parameters['v2']
         
-        self.commands += "C"
+        self.commands += "E"
+        self.commands[2] += "C"
         self.commands[2] += str(self.parameters['clean_s'])
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
@@ -391,7 +409,8 @@ class SWVExp(Experiment):
 
         self.data_extra = [[], []]  
         
-        self.commands += "S"
+        self.commands += "E"
+        self.commands[2] += "S"
         self.commands[2] += str(self.parameters['clean_s'])
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
@@ -444,7 +463,8 @@ class DPVExp(SWVExp):
 
         self.data_extra = [[], []]
         
-        self.commands += "D"
+        self.commands += "E"
+        self.commands[2] += "D"
         self.commands[2] += str(self.parameters['clean_s'])
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
@@ -475,7 +495,7 @@ class OCPExp(Experiment):
         self.main_pipe = main_pipe
         self.databytes = 8
         
-        self.commands = ["A", "P"]
+        self.commands = ["EA", "EP"]
     
         self.commands[0] += "2 " # input buffer
         self.commands[0] += "3 " # 2.5 Hz sample rate
diff --git a/dstat-interface/interface/pd.glade b/dstat-interface/interface/pd.glade
index 5e87db9..10be229 100644
--- a/dstat-interface/interface/pd.glade
+++ b/dstat-interface/interface/pd.glade
@@ -28,7 +28,7 @@
                   <object class="GtkTable" id="table1">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="n_rows">2</property>
+                    <property name="n_rows">6</property>
                     <property name="n_columns">2</property>
                     <property name="homogeneous">True</property>
                     <child>
@@ -78,18 +78,132 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkHScale" id="voltage_scale">
+                      <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="primary_icon_activatable">False</property>
+                        <property name="secondary_icon_activatable">False</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
                         <property name="adjustment">voltage_adjustment</property>
-                        <property name="restrict_to_fill_level">False</property>
-                        <property name="fill_level">100</property>
-                        <property name="round_digits">1</property>
-                        <property name="digits">0</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="right_attach">2</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>
+                      </object>
+                      <packing>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</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="right_attach">2</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</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>
+                      </object>
+                      <packing>
+                        <property name="top_attach">4</property>
+                        <property name="bottom_attach">5</property>
+                        <property name="x_options"/>
+                        <property name="y_options">GTK_FILL</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="invisible_char_set">True</property>
+                        <property name="primary_icon_activatable">False</property>
+                        <property name="secondary_icon_activatable">False</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">4</property>
+                        <property name="bottom_attach">5</property>
+                        <property name="x_options"/>
+                        <property name="y_options">GTK_FILL</property>
+                        <property name="y_padding">3</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>
+                      </object>
+                      <packing>
+                        <property name="top_attach">5</property>
+                        <property name="bottom_attach">6</property>
+                        <property name="x_options"/>
+                        <property name="y_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHSeparator" id="hseparator1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</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="right_attach">2</property>
+                        <property name="top_attach">5</property>
+                        <property name="bottom_attach">6</property>
                       </packing>
                     </child>
                   </object>
@@ -115,9 +229,6 @@
                     <property name="position">1</property>
                   </packing>
                 </child>
-                <child>
-                  <placeholder/>
-                </child>
               </object>
             </child>
           </object>
diff --git a/dstat-interface/main.py b/dstat-interface/main.py
index 1461a38..f1da0b3 100755
--- a/dstat-interface/main.py
+++ b/dstat-interface/main.py
@@ -608,7 +608,13 @@ class Main(object):
         """
         try:
             if self.recv_p.poll():
-                self.line, data = self.recv_p.recv()
+                incoming = self.recv_p.recv()
+                if isinstance(incoming, basestring): #test if incoming is str
+                    self.experiment_done()
+                    self.on_serial_disconnect_clicked()
+                    return False
+                
+                self.line, data = incoming
                 if self.line > self.lastdataline:
                     self.current_exp.data += [[], []]
                     if len(data) > 2:
-- 
GitLab