Skip to content

Commit dc4b67b

Browse files
authored
v1.1.0b1
version 1.1.0b1
2 parents 6139b45 + c10506b commit dc4b67b

File tree

6 files changed

+311
-56
lines changed

6 files changed

+311
-56
lines changed

pyobs_fli/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
__title__ = "FLI camera modules"
55

66
from .flicamera import FliCamera
7+
from .flifilterwheel import FliFilterWheel
78

89

910
__all__ = ["FliCamera"]

pyobs_fli/flibase.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import asyncio
2+
import logging
3+
from typing import Any, Optional, Union
4+
5+
from pyobs_fli.flidriver import DeviceType
6+
7+
log = logging.getLogger(__name__)
8+
9+
10+
class FliBaseMixin:
11+
"""A base class for pyobs module for FLI devices."""
12+
13+
__module__ = "pyobs_fli"
14+
15+
def __init__(
16+
self,
17+
dev_type: DeviceType,
18+
dev_name: Optional[str] = None,
19+
dev_path: Optional[str] = None,
20+
keep_alive_ping: int = 10,
21+
**kwargs: Any,
22+
):
23+
"""Initializes a new FliCamera.
24+
25+
If neither dev_name nor dev_path are given, the first found device is used.
26+
27+
Args:
28+
dev_type: Device type.
29+
dev_name: Optional name for device.
30+
dev_path: Optional path to device.
31+
keep_alive_ping: Interval for keep alive ping.
32+
"""
33+
from .flidriver import FliDriver # type: ignore
34+
35+
# variables
36+
self._dev_type = dev_type
37+
self._dev_name = dev_name
38+
self._dev_path = dev_path
39+
self._keep_alive_ping = keep_alive_ping
40+
self._driver: Optional[FliDriver] = None
41+
self._device: Optional[Any] = None
42+
43+
# keep alive
44+
self.add_background_task(self._keep_alive)
45+
46+
async def open(self) -> None:
47+
"""Open module."""
48+
from .flidriver import FliDriver
49+
50+
# list devices
51+
devices = FliDriver.list_devices(self._dev_type)
52+
if len(devices) == 0:
53+
raise ValueError("No FLI device found.")
54+
55+
# do we have a device name or path given?
56+
if self._dev_name is not None or self._dev_path is not None:
57+
# yes, find matching device
58+
for dev in devices:
59+
if dev.name.decode("utf-8") == self._dev_name or dev.filename.decode("utf-8") == self._dev_path:
60+
self._device = dev
61+
break
62+
else:
63+
raise ValueError("No matching device found, check dev_name/dev_path.")
64+
65+
else:
66+
# no, just pick first one
67+
self._device = devices[0]
68+
69+
# open driver
70+
log.info(
71+
'Opening connection to "%s" at %s...',
72+
self._device.name.decode("utf-8"),
73+
self._device.filename.decode("utf-8"),
74+
)
75+
self._driver = FliDriver(self._device)
76+
try:
77+
self._driver.open()
78+
except ValueError as e:
79+
raise ValueError("Could not open FLI camera: %s", e)
80+
81+
async def close(self) -> None:
82+
# not open?
83+
if self._driver is not None:
84+
# close connection
85+
self._driver.close()
86+
self._driver = None
87+
88+
async def _keep_alive(self) -> None:
89+
"""Keep connection to camera alive."""
90+
from .flidriver import FliDriver
91+
92+
while True:
93+
# is there a valid driver?
94+
if self._driver is not None:
95+
# then we should be able to call it
96+
try:
97+
self._driver.get_serial_string()
98+
except ValueError:
99+
# no? then reopen driver
100+
log.warning("Lost connection to camera, reopening it.")
101+
self._driver.close()
102+
self._driver = FliDriver(self._device)
103+
104+
await asyncio.sleep(self._keep_alive_ping)
105+
106+
107+
__all__ = ["FliBaseMixin"]

pyobs_fli/flicamera.py

Lines changed: 10 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,60 +10,41 @@
1010
from pyobs.images import Image
1111
from pyobs.utils.enums import ExposureStatus
1212

13+
from .flibase import FliBaseMixin
14+
1315

1416
log = logging.getLogger(__name__)
1517

1618

17-
class FliCamera(BaseCamera, ICamera, IWindow, IBinning, ICooling, IAbortable):
19+
class FliCamera(FliBaseMixin, BaseCamera, ICamera, IWindow, IBinning, ICooling, IAbortable):
1820
"""A pyobs module for FLI cameras."""
1921

2022
__module__ = "pyobs_fli"
2123

22-
def __init__(self, setpoint: float = -20.0, keep_alive_ping: int = 10, **kwargs: Any):
24+
def __init__(self, setpoint: float = -20.0, **kwargs: Any):
2325
"""Initializes a new FliCamera.
2426
2527
Args:
2628
setpoint: Cooling temperature setpoint.
27-
keep_alive_ping: Interval in seconds to ping camera.
2829
"""
2930
BaseCamera.__init__(self, **kwargs)
30-
from .flidriver import FliDriver # type: ignore
31+
FliBaseMixin.__init__(**kwargs)
3132

3233
# variables
33-
self._driver: Optional[FliDriver] = None
34-
self._device: Optional[Any] = None
3534
self._temp_setpoint: Optional[float] = setpoint
36-
self._keep_alive_ping = keep_alive_ping
3735

3836
# window and binning
3937
self._window = (0, 0, 0, 0)
4038
self._binning = (1, 1)
4139

42-
# keep alive
43-
self.add_background_task(self._keep_alive)
44-
4540
async def open(self) -> None:
4641
"""Open module."""
4742
await BaseCamera.open(self)
48-
from .flidriver import FliDriver
49-
50-
# list devices
51-
devices = FliDriver.list_devices()
52-
if len(devices) == 0:
53-
raise ValueError("No camera found.")
43+
await FliBaseMixin.open(self)
5444

55-
# open first one
56-
self._device = devices[0]
57-
log.info(
58-
'Opening connection to "%s" at %s...',
59-
self._device.name.decode("utf-8"),
60-
self._device.filename.decode("utf-8"),
61-
)
62-
self._driver = FliDriver(self._device)
63-
try:
64-
self._driver.open()
65-
except ValueError as e:
66-
raise ValueError("Could not open FLI camera: %s", e)
45+
# check
46+
if self._driver is None:
47+
raise ValueError("No driver found.")
6748

6849
# serial number
6950
serial = self._driver.get_serial_string()
@@ -79,30 +60,7 @@ async def open(self) -> None:
7960
async def close(self) -> None:
8061
"""Close the module."""
8162
await BaseCamera.close(self)
82-
83-
# not open?
84-
if self._driver is not None:
85-
# close connection
86-
self._driver.close()
87-
self._driver = None
88-
89-
async def _keep_alive(self) -> None:
90-
"""Keep connection to camera alive."""
91-
from .flidriver import FliDriver
92-
93-
while True:
94-
# is there a valid driver?
95-
if self._driver is not None:
96-
# then we should be able to call it
97-
try:
98-
self._driver.get_full_frame()
99-
except ValueError:
100-
# no? then reopen driver
101-
log.warning("Lost connection to camera, reopening it.")
102-
self._driver.close()
103-
self._driver = FliDriver(self._device)
104-
105-
await asyncio.sleep(self._keep_alive_ping)
63+
await FliBaseMixin.close(self)
10664

10765
async def get_full_frame(self, **kwargs: Any) -> Tuple[int, int, int, int]:
10866
"""Returns full size of CCD.

pyobs_fli/flidriver.pyx

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@ class FliTemperature(Enum):
2222
BASE = FLI_TEMPERATURE_BASE
2323

2424

25+
class DeviceType(Enum):
26+
CAMERA = FLIDEVICE_CAMERA
27+
FILTERWHEEL = FLIDEVICE_FILTERWHEEL
28+
29+
2530
cdef class FliDriver:
2631
"""Wrapper for the FLI driver."""
2732

2833
@staticmethod
29-
def list_devices() -> List[DeviceInfo]:
34+
def list_devices(device_type: DeviceType = DeviceType.CAMERA) -> List[DeviceInfo]:
3035
"""List all FLI USB cameras connected to this computer.
3136

3237
Returns:
@@ -39,7 +44,7 @@ cdef class FliDriver:
3944
cdef char name[1024]
4045

4146
# create list of USB camera
42-
if FLICreateList(FLIDOMAIN_USB | FLIDEVICE_CAMERA) != 0:
47+
if FLICreateList(FLIDOMAIN_USB | device_type.value) != 0:
4348
raise ValueError('Could not create list of FLI cameras.')
4449

4550
# init list of devices
@@ -368,6 +373,25 @@ cdef class FliDriver:
368373
if res != 0:
369374
raise ValueError('Could not set temperature.')
370375

376+
def get_model(self) -> str:
377+
"""Returns the model of the device.
378+
379+
Returns:
380+
str: Model of device.
381+
"""
382+
383+
# variables
384+
cdef char *model
385+
cdef size_t len
386+
387+
# get it
388+
res = FLIGetModel(self._device, model, len)
389+
if res != 0:
390+
raise ValueError('Could not fetch model.')
391+
392+
# return it
393+
return str(model)
394+
371395
def get_serial_string(self) -> str:
372396
"""Returns serial string for camera."""
373397

@@ -380,4 +404,34 @@ cdef class FliDriver:
380404
raise ValueError('Could not fetch serial string.')
381405

382406
# return it
383-
return str(serial)
407+
return bytes(serial).decode('utf-8')
408+
409+
def get_filter_pos(self) -> int:
410+
"""Returns current filter position.
411+
412+
Returns:
413+
Filter position.
414+
"""
415+
416+
# variables
417+
cdef long pos
418+
419+
# get it
420+
res = FLIGetFilterPos(self._device, &pos)
421+
if res != 0:
422+
raise ValueError('Could not fetch filter position.')
423+
424+
# return it
425+
return pos
426+
427+
def set_filter_pos(self, pos: int) -> None:
428+
"""Set filter position.
429+
430+
Args:
431+
pos: New filter position.
432+
"""
433+
434+
# set filter pos
435+
res = FLISetFilterPos(self._device, pos)
436+
if res != 0:
437+
raise ValueError('Could not set filter position.')

0 commit comments

Comments
 (0)