Loading openflexure_microscope/__init__.py +1 −1 Original line number Diff line number Diff line __all__ = ['Microscope', 'config'] __all__ = ['Microscope', 'config', 'task', 'lock'] __version__ = "0.1.0" from .microscope import Microscope Loading openflexure_microscope/api/app.py +13 −2 Original line number Diff line number Diff line Loading @@ -23,8 +23,9 @@ from flask_cors import CORS from openflexure_microscope.api.utilities import list_routes from openflexure_microscope import Microscope, config from openflexure_microscope.lock import LockError from openflexure_microscope.camera.pi import StreamingCamera from openflexure_stage import OpenFlexureStage from openflexure_microscope.stage.openflexure import Stage import atexit import logging, sys Loading Loading @@ -66,6 +67,16 @@ def _handle_http_exception(e): for code in default_exceptions: app.errorhandler(code)(_handle_http_exception) def _handle_lock_exception(e): return make_response( jsonify({ 'status_code': 423, 'error': e.code, 'details': e.message }), 423) app.errorhandler(LockError)(_handle_lock_exception) # After app starts, but before first request, attach hardware to global microscope @app.before_first_request Loading @@ -77,7 +88,7 @@ def attach_microscope(): logging.debug("Creating camera object...") api_camera = StreamingCamera(config=openflexurerc) logging.debug("Creating stage object...") api_stage = OpenFlexureStage("/dev/ttyUSB0") api_stage = Stage("/dev/ttyUSB0") logging.debug("Attaching devices to microscope...") api_microscope.attach( Loading openflexure_microscope/camera/base.py +3 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ except ImportError: from .capture import CaptureObject, capture_from_dict, BASE_CAPTURE_PATH from openflexure_microscope.config import USER_CONFIG_DIR from openflexure_microscope.utilities import entry_by_id from openflexure_microscope.lock import StrictLock def last_entry(object_list: list): Loading @@ -29,7 +30,6 @@ def last_entry(object_list: list): return None def generate_basename(): """Return a default filename based on the capture datetime""" return datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") Loading Loading @@ -87,6 +87,8 @@ class BaseCamera(object): self.thread = None #: Background thread reading frames from camera self.camera = None #: Camera object self.lock = StrictLock(timeout=1) #: Strict lock controlling thread access to camera hardware self.frame = None #: bytes: Current frame is stored here by background thread self.last_access = 0 #: time: Time of last client access to the camera self.event = CameraEvent() Loading openflexure_microscope/camera/pi.py +166 −160 Original line number Diff line number Diff line Loading @@ -201,6 +201,8 @@ class StreamingCamera(BaseCamera): paused_stream = False with self.lock: # Apply valid config params to Picamera object if not self.state['record_active']: # If not recording a video Loading Loading @@ -249,6 +251,7 @@ class StreamingCamera(BaseCamera): """ Change the camera zoom, handling recentering and scaling. """ with self.lock: self.state['zoom_value'] = float(zoom_value) if self.state['zoom_value'] < 1: self.state['zoom_value'] = 1 Loading Loading @@ -299,6 +302,7 @@ class StreamingCamera(BaseCamera): output_object (str/BytesIO): Target object. """ with self.lock: # Start recording method only if a current recording is not running if not self.state['record_active']: Loading Loading @@ -334,6 +338,7 @@ class StreamingCamera(BaseCamera): def stop_recording(self) -> bool: """Stop the last started video recording on splitter port 2.""" with self.lock: # Stop the camera video recording on port 2 logging.info("Stopping recording") self.camera.stop_recording(splitter_port=2) Loading Loading @@ -378,7 +383,6 @@ class StreamingCamera(BaseCamera): splitter_port (int): Splitter port to start recording on resolution ((int, int)): Resolution to set the camera to, before starting recording. Defaults to `self.config['video_resolution']`. """ # If no stream object exists if not hasattr(self, 'stream'): self.stream = io.BytesIO() # Create a stream object Loading Loading @@ -421,6 +425,7 @@ class StreamingCamera(BaseCamera): resize ((int, int)): Resize the captured image. """ with self.lock: # If output is a StreamObject if isinstance(output, CaptureObject): # Set target to capture stream Loading Loading @@ -459,6 +464,7 @@ class StreamingCamera(BaseCamera): use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster. resize ((int, int)): Resize the captured image. """ with self.lock: if use_video_port: resolution = self.config['video_resolution'] else: Loading Loading @@ -502,7 +508,7 @@ class StreamingCamera(BaseCamera): use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster. resize ((int, int)): Resize the captured image. """ with self.lock: if use_video_port: resolution = self.config['video_resolution'] else: Loading openflexure_microscope/lock.py 0 → 100644 +65 −0 Original line number Diff line number Diff line from threading import RLock, ThreadError class LockError(ThreadError): ERROR_CODES = { 'ACQUIRE_ERROR': "Unable to acquire. Lock in use by another thread.", 'IN_USE_ERROR': "Lock in use by another thread." } def __init__(self, code, lock): self.code = code if code in LockError.ERROR_CODES: self.message = LockError.ERROR_CODES[code] else: self.message = "Unknown error." print("{}: {}".format(self.code, self.message)) ThreadError.__init__(self) class StrictLock(object): def __init__(self, timeout=1): self._lock = RLock() self.timeout = timeout def acquire(self, blocking=True): return self._lock.acquire(blocking, timeout=self.timeout) def __enter__(self): result = self._lock.acquire(blocking=True, timeout=self.timeout) if result: return result else: raise LockError('ACQUIRE_ERROR', self) def __exit__(self, *args): self._lock.release() def release(self): self._lock.release() class CompositeLock(object): def __init__(self, locks, timeout=1): self.locks = locks self.timeout = timeout def acquire(self, blocking=True): return (lock.acquire(blocking=blocking, timeout=self.timeout) for lock in self.locks) def __enter__(self): result = (lock.acquire(blocking=True, timeout=self.timeout) for lock in self.locks) if all(result): return result else: msg = "Unable to acquire all locks {}.".format(self.locks) logging.error(msg) raise ThreadError(msg) def __exit__(self, *args): for lock in self.locks: lock.release() def release(self): for lock in self.locks: lock.release() No newline at end of file Loading
openflexure_microscope/__init__.py +1 −1 Original line number Diff line number Diff line __all__ = ['Microscope', 'config'] __all__ = ['Microscope', 'config', 'task', 'lock'] __version__ = "0.1.0" from .microscope import Microscope Loading
openflexure_microscope/api/app.py +13 −2 Original line number Diff line number Diff line Loading @@ -23,8 +23,9 @@ from flask_cors import CORS from openflexure_microscope.api.utilities import list_routes from openflexure_microscope import Microscope, config from openflexure_microscope.lock import LockError from openflexure_microscope.camera.pi import StreamingCamera from openflexure_stage import OpenFlexureStage from openflexure_microscope.stage.openflexure import Stage import atexit import logging, sys Loading Loading @@ -66,6 +67,16 @@ def _handle_http_exception(e): for code in default_exceptions: app.errorhandler(code)(_handle_http_exception) def _handle_lock_exception(e): return make_response( jsonify({ 'status_code': 423, 'error': e.code, 'details': e.message }), 423) app.errorhandler(LockError)(_handle_lock_exception) # After app starts, but before first request, attach hardware to global microscope @app.before_first_request Loading @@ -77,7 +88,7 @@ def attach_microscope(): logging.debug("Creating camera object...") api_camera = StreamingCamera(config=openflexurerc) logging.debug("Creating stage object...") api_stage = OpenFlexureStage("/dev/ttyUSB0") api_stage = Stage("/dev/ttyUSB0") logging.debug("Attaching devices to microscope...") api_microscope.attach( Loading
openflexure_microscope/camera/base.py +3 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ except ImportError: from .capture import CaptureObject, capture_from_dict, BASE_CAPTURE_PATH from openflexure_microscope.config import USER_CONFIG_DIR from openflexure_microscope.utilities import entry_by_id from openflexure_microscope.lock import StrictLock def last_entry(object_list: list): Loading @@ -29,7 +30,6 @@ def last_entry(object_list: list): return None def generate_basename(): """Return a default filename based on the capture datetime""" return datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") Loading Loading @@ -87,6 +87,8 @@ class BaseCamera(object): self.thread = None #: Background thread reading frames from camera self.camera = None #: Camera object self.lock = StrictLock(timeout=1) #: Strict lock controlling thread access to camera hardware self.frame = None #: bytes: Current frame is stored here by background thread self.last_access = 0 #: time: Time of last client access to the camera self.event = CameraEvent() Loading
openflexure_microscope/camera/pi.py +166 −160 Original line number Diff line number Diff line Loading @@ -201,6 +201,8 @@ class StreamingCamera(BaseCamera): paused_stream = False with self.lock: # Apply valid config params to Picamera object if not self.state['record_active']: # If not recording a video Loading Loading @@ -249,6 +251,7 @@ class StreamingCamera(BaseCamera): """ Change the camera zoom, handling recentering and scaling. """ with self.lock: self.state['zoom_value'] = float(zoom_value) if self.state['zoom_value'] < 1: self.state['zoom_value'] = 1 Loading Loading @@ -299,6 +302,7 @@ class StreamingCamera(BaseCamera): output_object (str/BytesIO): Target object. """ with self.lock: # Start recording method only if a current recording is not running if not self.state['record_active']: Loading Loading @@ -334,6 +338,7 @@ class StreamingCamera(BaseCamera): def stop_recording(self) -> bool: """Stop the last started video recording on splitter port 2.""" with self.lock: # Stop the camera video recording on port 2 logging.info("Stopping recording") self.camera.stop_recording(splitter_port=2) Loading Loading @@ -378,7 +383,6 @@ class StreamingCamera(BaseCamera): splitter_port (int): Splitter port to start recording on resolution ((int, int)): Resolution to set the camera to, before starting recording. Defaults to `self.config['video_resolution']`. """ # If no stream object exists if not hasattr(self, 'stream'): self.stream = io.BytesIO() # Create a stream object Loading Loading @@ -421,6 +425,7 @@ class StreamingCamera(BaseCamera): resize ((int, int)): Resize the captured image. """ with self.lock: # If output is a StreamObject if isinstance(output, CaptureObject): # Set target to capture stream Loading Loading @@ -459,6 +464,7 @@ class StreamingCamera(BaseCamera): use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster. resize ((int, int)): Resize the captured image. """ with self.lock: if use_video_port: resolution = self.config['video_resolution'] else: Loading Loading @@ -502,7 +508,7 @@ class StreamingCamera(BaseCamera): use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster. resize ((int, int)): Resize the captured image. """ with self.lock: if use_video_port: resolution = self.config['video_resolution'] else: Loading
openflexure_microscope/lock.py 0 → 100644 +65 −0 Original line number Diff line number Diff line from threading import RLock, ThreadError class LockError(ThreadError): ERROR_CODES = { 'ACQUIRE_ERROR': "Unable to acquire. Lock in use by another thread.", 'IN_USE_ERROR': "Lock in use by another thread." } def __init__(self, code, lock): self.code = code if code in LockError.ERROR_CODES: self.message = LockError.ERROR_CODES[code] else: self.message = "Unknown error." print("{}: {}".format(self.code, self.message)) ThreadError.__init__(self) class StrictLock(object): def __init__(self, timeout=1): self._lock = RLock() self.timeout = timeout def acquire(self, blocking=True): return self._lock.acquire(blocking, timeout=self.timeout) def __enter__(self): result = self._lock.acquire(blocking=True, timeout=self.timeout) if result: return result else: raise LockError('ACQUIRE_ERROR', self) def __exit__(self, *args): self._lock.release() def release(self): self._lock.release() class CompositeLock(object): def __init__(self, locks, timeout=1): self.locks = locks self.timeout = timeout def acquire(self, blocking=True): return (lock.acquire(blocking=blocking, timeout=self.timeout) for lock in self.locks) def __enter__(self): result = (lock.acquire(blocking=True, timeout=self.timeout) for lock in self.locks) if all(result): return result else: msg = "Unable to acquire all locks {}.".format(self.locks) logging.error(msg) raise ThreadError(msg) def __exit__(self, *args): for lock in self.locks: lock.release() def release(self): for lock in self.locks: lock.release() No newline at end of file