Skip to content

Commit

Permalink
Halt/terminate/stop pump working
Browse files Browse the repository at this point in the history
Also, threading.event test script
Resolves #32
  • Loading branch information
dpk9 committed Sep 5, 2024
1 parent 377644c commit 953685a
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 42 deletions.
80 changes: 38 additions & 42 deletions SEC_GUI/octasome_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def __init__(self, debug=False, busy_debug=False, file_name=None):
# self.openFile(self.write)
self.thread_id = 0
self.baud = None
self.halted = threading.Event()
# self.max_steps = 6000

# connect GUI signals to methods
Expand All @@ -58,9 +59,9 @@ def __init__(self, debug=False, busy_debug=False, file_name=None):
# toggle column checkbox states:
self.ui.allCheckBox.stateChanged.connect(self.enableColumnSelect)
# send halt command to pump:
self.ui.stopButton.clicked.connect(self.stopPump)
self.ui.stopButton.clicked.connect(self.haltPumpThread)
# send halt command to pump via menu:
self.ui.actionTerminate.triggered.connect(self.stopPump)
self.ui.actionTerminate.triggered.connect(self.haltPumpThread)
# quit application
self.ui.actionQuit.triggered.connect(qApp.quit)
# query pump
Expand Down Expand Up @@ -367,6 +368,7 @@ def queryPump(self):
return status_bit

def fillPumpThread(self):
self.halted.clear()
thread = threading.Thread(target=self.fillPump)
thread.name = "thread-{:03d}".format(self.thread_id)
self.thread_id += 1
Expand All @@ -387,6 +389,7 @@ def fillPump(self):
return

def emptyPumpThread(self):
self.halted.clear()
thread = threading.Thread(target=self.emptyPump)
thread.name = "thread-{:03d}".format(self.thread_id)
self.thread_id += 1
Expand All @@ -407,6 +410,7 @@ def emptyPump(self):
return

def primeLinesThread(self):
self.halted.clear()
thread = threading.Thread(target=self.primeLines)
thread.name = "thread-{:03d}".format(self.thread_id)
self.thread_id += 1
Expand All @@ -430,6 +434,7 @@ def primeLines(self):
return

def emptyLinesThread(self):
self.halted.clear()
thread = threading.Thread(target=self.emptyLines)
thread.name = "thread-{:03d}".format(self.thread_id)
self.thread_id += 1
Expand All @@ -455,6 +460,7 @@ def emptyLines(self):
return

def emptyPumpLinesThread(self):
self.halted.clear()
thread = threading.Thread(target=self.emptyPumpLines)
thread.name = "thread-{:03d}".format(self.thread_id)
self.thread_id += 1
Expand All @@ -473,32 +479,8 @@ def emptyPumpLines(self):
command_string += "I" + str(column+2) + "P" + str(750)
command_string += "I1V" + str(dispensespeed) + "A0"
self.write(command_string)
# self.emptyPump()
# # do not build and send command until pump is no longer busy
# self._waitReady(10, 1)
# self.emptyLines()
# self._waitReady(10, 1)
# self.emptyPump()
return

def cleanLines(self):
"""clean lines by dispensing a fixed volume through each channel"""
# check if pump is busy
if self.checkBusy():
return
print("{}: cleanLines".format(threading.current_thread().name))
drawspeed = int(self.ui.drawSpeedSpinBox.value()) # get speed from GUI
dispensespeed = int(self.ui.dispenseSpeedSpinBox.value()) # get speed from GUI
command_string = "/1I1V" + str(drawspeed) + "A6000"
# build command string
command_string += "V" + str(dispensespeed)
for column in range(8):
command_string += "I" + str(column+2) + "D" + str(750)
command_string += "I1V" + str(drawspeed)# + "A6000"
self.write(command_string)
return


def enableColumnSelect(self):
"""toggles column checkbox enable states based off of "all" checkbox"""
if self.ui.allCheckBox.checkState():
Expand All @@ -509,14 +491,14 @@ def enableColumnSelect(self):
box.setEnabled(True)

def dispenseThread(self):
self.halted.clear()
thread = threading.Thread(target=self.dispense)
thread.name = "thread-{:03d}".format(self.thread_id)
self.thread_id += 1
thread.start()

def dispense(self):
"""dispenses to the columns (all or individually selected)"""
# TODO: make sure this deals with all reasonable cases.. may want to query pump status before commands are written
# check if pump is busy
thread_name = threading.current_thread().name
print("{}: dispense() called NOW!!!!".format(thread_name))
Expand Down Expand Up @@ -560,7 +542,9 @@ def dispense(self):
steps_remaining = total_steps
# do the dispense in a loop
while steps_remaining > 0:
# cmd_str = "/1"
if self.halted.is_set():
print("{}: dispense() halted {}".format(thread_name, self.halted.is_set()))
return
# if more than 1 stroke req'd, full stroke & reduce steps_remaining
if steps_remaining > 6000:
steps = 6000
Expand All @@ -584,12 +568,21 @@ def dispense(self):
self._nonBlockingTime(3)
# self._waitReady(delay=3)
print("{}: in while loop".format(thread_name))
if self.halted.is_set():
print("{}: dispense() halted {}".format(thread_name, self.halted.is_set()))
return
self._nonBlockingTime(.5)
if self.halted.is_set():
print("{}: dispense() halted {}".format(thread_name, self.halted.is_set()))
return
# self._waitReady(delay=.5)
self.write(cmd_str)
sleeplength = steps/drawspeed + steps/dispensespeed + 1.5
sleeplength = steps/drawspeed + steps/dispensespeed + 1
# print(sleeplength)
self._nonBlockingTime(sleeplength)
if self.halted.is_set():
print("{}: dispense() halted {}".format(thread_name, self.halted.is_set()))
return
# self._waitReady(delay=sleeplength)
print("{}: Dispense done".format(thread_name))
return
Expand All @@ -604,25 +597,27 @@ def getColumnCheckBoxesSelected(self):
result.append(checkbox.isChecked())
return result

def stopPumpThread(self):
thread = threading.Thread(target=self.stopPump)
def haltPumpThread(self):
self.halted.set()
thread = threading.Thread(target=self.haltPump)
thread.name = "thread-{:03d}".format(self.thread_id)
self.thread_id += 1
thread.start()

def stopPump(self):
def haltPump(self):
"""interrupts the pump and stops operation"""
print("{}: STOP PUMP!!!!".format(threading.current_thread().name))
cmd = "/1TR\r\n"
print("{}: STOP PUMP!!!! halted = {}".format(threading.current_thread().name, self.halted.is_set()))
cmd = "/1T"
# cmd = "/1TR\r\n"
if self.debug:
self.dbprint("stopped")
print(cmd)
if self.file_name:
self.file.write("> {}".format(cmd))
else:
print("serial.write({})".format(cmd.encode()))
# print("serial.write({})".format(cmd.encode()))
print("baud: {}".format(self.baud))
self.serial.write(cmd.encode())
self.write(cmd)
return

def volumeToSteps(self, volume_ml):
Expand Down Expand Up @@ -661,6 +656,9 @@ def checkBusy(self, attempts=3, timeout=.1, busy_debug=None, popup=True):
return False
# Try (attempts) times and wait (timeout) sec between
for attempt in range(attempts):
if self.halted.is_set():
print("{}: checkBusy halted {}".format(thread_name, self.halted.is_set()))
return
print("{}: Busy check {}".format(thread_name, attempt))
# check for debugging busy flag or try for real
if busy_debug:
Expand Down Expand Up @@ -718,16 +716,14 @@ def _nonBlockingTime(self, seconds):
thread_name = threading.current_thread().name
print("{}: _nonBlockingTime waiting {} sec...\n".format(thread_name, seconds))
for x in range(int(seconds*granularity)):
self.dbprint("halted = {}".format(self.halted.is_set()))
time.sleep(1.0/granularity)
if self.halted.is_set():
print("{}: _nonBlockingTime halted {}".format(thread_name, self.halted.is_set()))
return
print("{}: _nonBlockingTime done waiting".format(thread_name))
return

# def openFile(self, filename):
# """Open the file `filename` (and create if needed) for saving serial
# commands sent and received
# """
# self.file = open(filename, "w")

# def closeEvent(self, event):
def exitCommands(self):
"""Things to run at application exit"""
Expand Down
35 changes: 35 additions & 0 deletions dev/thread_event_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import threading
import time


class MyClass:
def __init__(self):
super(MyClass, self).__init__()
self.event = threading.Event()


def delay(self):
time.sleep(1.2)
self.event.set()
return

def looper(self):
granularity = 4
for x in range(4*granularity):
time.sleep(1.0/granularity)
print(self.event.is_set())
if self.event.is_set():
return
return

def auto(self):
self.event.clear()
thread1 = threading.Thread(target=self.looper)
thread2 = threading.Thread(target=self.delay)
thread1.start()
time.sleep(0.5)
thread2.start()
return

mc = MyClass()
mc.auto()

0 comments on commit 953685a

Please sign in to comment.