# Path: concert/coroutines/base.py
# def run_in_executor(func, *args):
#     """Run a blocking function *func* with signature func(\*args) in an executor."""
#     # Leave this here for now, if there are problems with the normal run_in_executor returning a
#     # future then let's re-visit
#     # """Run a blocking function *func* with signature func(*args) in an executor, wrap the future
#     # into a real coroutine and return it.
#     # """
#     # async def make_coro():
#     #     loop = asyncio.get_running_loop()
#     #     future = loop.run_in_executor(None, func, *args)
#     #
#     #     try:
#     #         return await future
#     #     except asyncio.CancelledError:
#     #         # Wait for the future to finish even if we are cancelled.
#     #         LOG.log(AIODEBUG, f'{func.__name__} waiting for concurrent.Future')
#     #         return await future
#     # return make_coro()
#     loop = asyncio.get_event_loop()
# 
#     return loop.run_in_executor(None, func, *args)
# 
# Path: concert/quantities.py

# 
# Path: concert/base.py
# def transition(immediate=None, target=None):
#     """Change software state of a device to *immediate*. After the function execution finishes
#     change the state to *target*. On :py:class:`.asyncio.CancelledError`, state is set to *target*
#     and cleanup logic must take place in the callable to be wrapped.
#     """
#     def wrapped(func):
#         @functools.wraps(func)
#         async def call_func(instance, *args, **kwargs):
#             if 'state' not in instance:
#                 raise FSMError('Changing state requires state parameter')
# 
#             # Store the original in case target is None
#             target_state = target if target else await instance['state'].get()
# 
#             if immediate:
#                 setattr(instance, '_state_value', immediate)
# 
#             try:
#                 result = await _execute_func(func, instance, *args, **kwargs)
#                 setattr(instance, '_state_value', target_state)
#             except StateError as error:
#                 setattr(instance, '_state_value', error.state)
#                 raise error
#             except asyncio.CancelledError:
#                 # If *func* is cancelled, *func* must make sure that all cleanup except state update
#                 # happens. If even the state should have some special value, then do not use
#                 # *transition* at all and implement everything in *func*.
#                 setattr(instance, '_state_value', target_state)
#                 raise
# 
#             return result
# 
#         return call_func
# 
#     return wrapped
# 
# class Quantity(Parameter):
# 
#     """A :class:`.Parameter` associated with a unit."""
# 
#     def __init__(self, unit, fget=None, fset=None, fget_target=None, lower=None, upper=None,
#                  data=None, check=None, external_lower_getter=None, external_upper_getter=None,
#                  user_lower_getter=None, user_lower_setter=None, user_upper_getter=None,
#                  user_upper_setter=None, help=None):
#         """
#         *fget*, *fset*, *data*, *check* and *help* are identical to the
#         :class:`.Parameter` constructor arguments.
# 
#         *unit* is a Pint quantity. *lower* and *upper* denote soft limits
#         between the :class:`.Quantity` values can lie.
#         """
#         super(Quantity, self).__init__(fget=fget, fset=fset, fget_target=fget_target, data=data,
#                                        check=check, help=help)
#         self.unit = unit
# 
#         self.upper = upper
#         self.lower = lower
#         self.external_lower_getter = external_lower_getter
#         self.external_upper_getter = external_upper_getter
#         self.user_lower_getter = user_lower_getter
#         self.user_lower_setter = user_lower_setter
#         self.user_upper_getter = user_upper_getter
#         self.user_upper_setter = user_upper_setter
# 
#     def convert(self, value):
#         return value.to(self.unit)
# 
# Path: concert/devices/cameras/base.py
# LOG = logging.getLogger(__name__)
# class CameraError(Exception):
# class Camera(Device):
# class BufferedMixin(Device):
#     def __init__(self):
#     async def start_recording(self):
#     async def stop_recording(self):
#     async def recording(self):
#     async def trigger(self):
#     async def grab(self):
#     async def stream(self):
#     async def _get_trigger_source(self):
#     async def _set_trigger_source(self, source):
#     async def _record_real(self):
#     async def _stop_real(self):
#     async def _trigger_real(self):
#     async def _grab_real(self):
#     def readout_buffer(self, *args, **kwargs):
#     async def _readout_real(self, *args, **kwargs):
# 
# Path: concert/readers.py
# class TiffSequenceReader(FileSequenceReader):
#     def __init__(self, file_prefix, ext='.tif'):
#         super(TiffSequenceReader, self).__init__(file_prefix, ext=ext)
# 
#     def _open_real(self, filename):
#         import tifffile
#         return tifffile.TiffFile(filename)
# 
#     def _close_real(self):
#         self._file.close()
# 
#     def _get_num_images_in_file_real(self):
#         return len(self._file.pages)
# 
#     def _read_real(self, index):
#         return self._file.pages[index].asarray()


import asyncio
import time
import numpy as np
from concert.coroutines.base import run_in_executor
from concert.quantities import q
from concert.base import transition, Quantity
from concert.devices.cameras import base
from concert.readers import TiffSequenceReader
"""This module provides a simple dummy camera."""


class Base(base.Camera):

    exposure_time = Quantity(q.s)
    sensor_pixel_width = Quantity(q.micrometer)
    sensor_pixel_height = Quantity(q.micrometer)
    roi_x0 = Quantity(q.pixel)
    roi_y0 = Quantity(q.pixel)
    roi_width = Quantity(q.pixel)
    roi_height = Quantity(q.pixel)

    def __init__(self):
        super(Base, self).__init__()
        self._frame_rate = 1000 / q.s
        self._trigger_source = self.trigger_sources.AUTO

# Path: concert/coroutines/base.py
# def run_in_executor(func, *args):
#     """Run a blocking function *func* with signature func(\*args) in an executor."""
#     # Leave this here for now, if there are problems with the normal run_in_executor returning a
#     # future then let's re-visit
#     # """Run a blocking function *func* with signature func(*args) in an executor, wrap the future
#     # into a real coroutine and return it.
#     # """
#     # async def make_coro():
#     #     loop = asyncio.get_running_loop()
#     #     future = loop.run_in_executor(None, func, *args)
#     #
#     #     try:
#     #         return await future
#     #     except asyncio.CancelledError:
#     #         # Wait for the future to finish even if we are cancelled.
#     #         LOG.log(AIODEBUG, f'{func.__name__} waiting for concurrent.Future')
#     #         return await future
#     # return make_coro()
#     loop = asyncio.get_event_loop()
# 
#     return loop.run_in_executor(None, func, *args)
# 
# Path: concert/quantities.py

# 
# Path: concert/base.py
# def transition(immediate=None, target=None):
#     """Change software state of a device to *immediate*. After the function execution finishes
#     change the state to *target*. On :py:class:`.asyncio.CancelledError`, state is set to *target*
#     and cleanup logic must take place in the callable to be wrapped.
#     """
#     def wrapped(func):
#         @functools.wraps(func)
#         async def call_func(instance, *args, **kwargs):
#             if 'state' not in instance:
#                 raise FSMError('Changing state requires state parameter')
# 
#             # Store the original in case target is None
#             target_state = target if target else await instance['state'].get()
# 
#             if immediate:
#                 setattr(instance, '_state_value', immediate)
# 
#             try:
#                 result = await _execute_func(func, instance, *args, **kwargs)
#                 setattr(instance, '_state_value', target_state)
#             except StateError as error:
#                 setattr(instance, '_state_value', error.state)
#                 raise error
#             except asyncio.CancelledError:
#                 # If *func* is cancelled, *func* must make sure that all cleanup except state update
#                 # happens. If even the state should have some special value, then do not use
#                 # *transition* at all and implement everything in *func*.
#                 setattr(instance, '_state_value', target_state)
#                 raise
# 
#             return result
# 
#         return call_func
# 
#     return wrapped
# 
# class Quantity(Parameter):
# 
#     """A :class:`.Parameter` associated with a unit."""
# 
#     def __init__(self, unit, fget=None, fset=None, fget_target=None, lower=None, upper=None,
#                  data=None, check=None, external_lower_getter=None, external_upper_getter=None,
#                  user_lower_getter=None, user_lower_setter=None, user_upper_getter=None,
#                  user_upper_setter=None, help=None):
#         """
#         *fget*, *fset*, *data*, *check* and *help* are identical to the
#         :class:`.Parameter` constructor arguments.
# 
#         *unit* is a Pint quantity. *lower* and *upper* denote soft limits
#         between the :class:`.Quantity` values can lie.
#         """
#         super(Quantity, self).__init__(fget=fget, fset=fset, fget_target=fget_target, data=data,
#                                        check=check, help=help)
#         self.unit = unit
# 
#         self.upper = upper
#         self.lower = lower
#         self.external_lower_getter = external_lower_getter
#         self.external_upper_getter = external_upper_getter
#         self.user_lower_getter = user_lower_getter
#         self.user_lower_setter = user_lower_setter
#         self.user_upper_getter = user_upper_getter
#         self.user_upper_setter = user_upper_setter
# 
#     def convert(self, value):
#         return value.to(self.unit)
# 
# Path: concert/devices/cameras/base.py
# LOG = logging.getLogger(__name__)
# class CameraError(Exception):
# class Camera(Device):
# class BufferedMixin(Device):
#     def __init__(self):
#     async def start_recording(self):
#     async def stop_recording(self):
#     async def recording(self):
#     async def trigger(self):
#     async def grab(self):
#     async def stream(self):
#     async def _get_trigger_source(self):
#     async def _set_trigger_source(self, source):
#     async def _record_real(self):
#     async def _stop_real(self):
#     async def _trigger_real(self):
#     async def _grab_real(self):
#     def readout_buffer(self, *args, **kwargs):
#     async def _readout_real(self, *args, **kwargs):
# 
# Path: concert/readers.py
# class TiffSequenceReader(FileSequenceReader):
#     def __init__(self, file_prefix, ext='.tif'):
#         super(TiffSequenceReader, self).__init__(file_prefix, ext=ext)
# 
#     def _open_real(self, filename):
#         import tifffile
#         return tifffile.TiffFile(filename)
# 
#     def _close_real(self):
#         self._file.close()
# 
#     def _get_num_images_in_file_real(self):
#         return len(self._file.pages)
# 
#     def _read_real(self, index):
#         return self._file.pages[index].asarray()


# Path: concert/devices/cameras/dummy.py
import asyncio
import time
import numpy as np
from concert.coroutines.base import run_in_executor
from concert.quantities import q
from concert.base import transition, Quantity
from concert.devices.cameras import base
from concert.readers import TiffSequenceReader

"""This module provides a simple dummy camera."""


class Base(base.Camera):

    exposure_time = Quantity(q.s)
    sensor_pixel_width = Quantity(q.micrometer)
    sensor_pixel_height = Quantity(q.micrometer)
    roi_x0 = Quantity(q.pixel)
    roi_y0 = Quantity(q.pixel)
    roi_width = Quantity(q.pixel)
    roi_height = Quantity(q.pixel)

    def __init__(self):
        super(Base, self).__init__()
        self._frame_rate = 1000 / q.s
        self._trigger_source = self.trigger_sources.AUTO

        self._exposure_time = 1 * q.ms