Skip to content

Commit d1a0b99

Browse files
Merged in camera-hang-fix (pull request #83)
Fix issue #36: BLACS freezing in IMAQdxCamera continuous acquisition. Approved-by: David Meyer
2 parents a609688 + 18ba0b7 commit d1a0b99

File tree

2 files changed

+24
-24
lines changed

2 files changed

+24
-24
lines changed

IMAQdxCamera/blacs_tabs.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
import numpy as np
2424

25-
from qtutils import UiLoader, inmain_later
25+
from qtutils import UiLoader, inmain_decorator
2626
import qtutils.icons
2727
from qtutils.qt import QtWidgets, QtGui, QtCore
2828
import pyqtgraph as pg
@@ -58,7 +58,13 @@ def __init__(self, image_view, label_fps):
5858
self.frame_rate = None
5959
self.update_event = None
6060

61+
@inmain_decorator(wait_for_return=True)
6162
def handler(self, data):
63+
# Acknowledge immediately so that the worker process can begin acquiring the
64+
# next frame. This increases the possible frame rate since we may render a frame
65+
# whilst acquiring the next, but does not allow us to accumulate a backlog since
66+
# only one call to this method may occur at a time.
67+
self.send([b'ok'])
6268
md = json.loads(data[0])
6369
image = np.frombuffer(memoryview(data[1]), dtype=md['dtype'])
6470
image = image.reshape(md['shape'])
@@ -71,25 +77,6 @@ def handler(self, data):
7177
else:
7278
self.frame_rate = 1 / dt
7379
self.last_frame_time = this_frame_time
74-
# Wait for the previous update to compete so we don't accumulate a backlog:
75-
if self.update_event is not None:
76-
while True:
77-
# Don't block, and check for self.stopping regularly in case we are
78-
# shutting down. Otherwise if shutdown is called from the main thread we
79-
# would deadlock.
80-
try:
81-
self.update_event.get(timeout=0.1)
82-
break
83-
except Empty:
84-
if self.stopping:
85-
return
86-
self.update_event = inmain_later(self.update, image, self.frame_rate)
87-
return [b'ok']
88-
89-
def update(self, image, frame_rate):
90-
if not self.mainloop_thread.is_alive():
91-
# We have been shut down. Nothing to do here.
92-
return
9380
if self.image_view.image is None:
9481
# First time setting an image. Do autoscaling etc:
9582
self.image_view.setImage(image.swapaxes(-1, -2))
@@ -99,8 +86,21 @@ def update(self, image, frame_rate):
9986
image.swapaxes(-1, -2), autoRange=False, autoLevels=False
10087
)
10188
# Update fps indicator:
102-
if frame_rate is not None:
103-
self.label_fps.setText(f"{frame_rate:.01f} fps")
89+
if self.frame_rate is not None:
90+
self.label_fps.setText(f"{self.frame_rate:.01f} fps")
91+
92+
# Tell Qt to send posted events immediately to prevent a backlog of paint events
93+
# and other low-priority events. It seems that we cannot make our qtutils
94+
# CallEvents (which are used to call this method in the main thread) low enough
95+
# priority to ensure all other occur before our next call to self.handler()
96+
# runs. This may be because the CallEvents used by qtutils.invoke_in_main have
97+
# their own event handler (qtutils.invoke_in_main.Caller), perhaps posted event
98+
# priorities are only meaningful within the context of a single event handler,
99+
# and not for the Qt event loop as a whole. In any case, this seems to fix it.
100+
# Manually calling this is usually a sign of bad coding, but I think it is the
101+
# right solution to this problem. This solves issue #36.
102+
QtGui.QApplication.instance().sendPostedEvents()
103+
return self.NO_RESPONSE
104104

105105

106106
class IMAQdxCameraTab(DeviceTab):
@@ -286,4 +286,4 @@ def restart(self, *args, **kwargs):
286286
# Must manually stop the receiving server upon tab restart, otherwise it does
287287
# not get cleaned up:
288288
self.image_receiver.shutdown()
289-
return DeviceTab.restart(self, *args, **kwargs)
289+
return DeviceTab.restart(self, *args, **kwargs)

__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
check_version('qtutils', '2.0.0', '3.0.0')
2727
check_version('labscript', '2.6', '3')
2828
check_version('blacs', '2.7.0', '3.0.0')
29-
check_version('zprocess', '2.2.7', '3')
29+
check_version('zprocess', '2.17.0', '3')
3030
check_version('numpy', '1.15.1', '2')
3131

3232

0 commit comments

Comments
 (0)