Loading noctua/devices/atik.py +61 −9 Original line number Diff line number Diff line Loading @@ -52,11 +52,17 @@ class Camera(BaseDevice): self._props = ArtemisProperties() self._subframe = [0, 0, 0, 0] self._last_exptime = None self._last_frametype = None self._last_datetime = None try: self._lib = ctypes.CDLL("/usr/lib/libatikcameras.so") self._lib.ArtemisConnect.restype = ctypes.c_void_p self._lib.ArtemisImageBuffer.restype = ctypes.c_void_p self._lib.ArtemisExposureTimeRemaining.restype = ctypes.c_float self._lib.ArtemisLastExposureDuration.restype = ctypes.c_float self._lib.ArtemisLastStartTime.restype = ctypes.c_char_p except Exception as e: log.error(f"Atik SDK load failed: {e}") Loading Loading @@ -120,7 +126,9 @@ class Camera(BaseDevice): def start(self, duration, frametype, datetime=None): h = self._check_connection() if not h: return # Using put internally for consistency self._last_exptime = duration self._last_frametype = frametype self._last_datetime = datetime is_dark = True if frametype in [0, 2, "Dark", "Bias"] else False self._lib.ArtemisSetDarkMode(h, is_dark) self._lib.ArtemisStartExposure(h, ctypes.c_float(duration)) Loading @@ -141,13 +149,57 @@ class Camera(BaseDevice): ctypes.byref(bx), ctypes.byref(by)) buf_ptr = self._lib.ArtemisImageBuffer(h) if buf_ptr: if not buf_ptr: return from pathlib import Path from ..config.constants import frame_type as _frame_type Path(filepath).parent.mkdir(parents=True, exist_ok=True) size = w.value * h_img.value buffer = (ctypes.c_uint16 * size).from_address(buf_ptr) data = np.frombuffer(buffer, dtype=np.uint16).reshape(h_img.value, w.value) fits.PrimaryHDU(data).writeto(filepath, overwrite=True) hdu = fits.PrimaryHDU(data) hdr = hdu.header hdr['INSTRUME'] = (self._props.Description.decode(), "Camera model") exptime = self._lib.ArtemisLastExposureDuration(h) if exptime == 0.0 and self._last_exptime is not None: exptime = self._last_exptime hdr['EXPTIME'] = (float(exptime), "[s] Exposure duration") start_time_bytes = self._lib.ArtemisLastStartTime(h) start_ms = self._lib.ArtemisLastStartTimeMilliseconds(h) if start_time_bytes: hdr['DATE-OBS'] = (f"{start_time_bytes.decode()}.{start_ms:03d}", "(UTC) Date the exposure was started") elif self._last_datetime is not None: hdr['DATE-OBS'] = (str(self._last_datetime), "(UTC) Date the exposure was started") ccd_temp = ctypes.c_int() self._lib.ArtemisTemperatureSensorInfo(h, 1, ctypes.byref(ccd_temp)) hdr['CCD-TEMP'] = (ccd_temp.value / 100.0, "[C] CCD temperature") flags, level, minl, maxl, setp = [ctypes.c_int() for _ in range(5)] self._lib.ArtemisCoolingInfo(h, ctypes.byref(flags), ctypes.byref(level), ctypes.byref(minl), ctypes.byref(maxl), ctypes.byref(setp)) hdr['SET-TEMP'] = (setp.value / 100.0, "[C] CCD setpoint temperature") hdr['XPIXSZ'] = (self._props.PixelMicronsX, "[um] Pixel X size") hdr['YPIXSZ'] = (self._props.PixelMicronsY, "[um] Pixel Y size") hdr['XBINNING'] = (bx.value, "X binning factor") hdr['YBINNING'] = (by.value, "Y binning factor") hdr['XORGSUBF'] = (self._subframe[0], "[px] Subframe X origin (unbinned)") hdr['YORGSUBF'] = (self._subframe[1], "[px] Subframe Y origin (unbinned)") ft = self._last_frametype hdr['IMAGETYP'] = (_frame_type.get(ft, str(ft)) if ft is not None else "", "Image type") hdu.writeto(filepath, overwrite=True) # --- Windowing Methods --- Loading Loading
noctua/devices/atik.py +61 −9 Original line number Diff line number Diff line Loading @@ -52,11 +52,17 @@ class Camera(BaseDevice): self._props = ArtemisProperties() self._subframe = [0, 0, 0, 0] self._last_exptime = None self._last_frametype = None self._last_datetime = None try: self._lib = ctypes.CDLL("/usr/lib/libatikcameras.so") self._lib.ArtemisConnect.restype = ctypes.c_void_p self._lib.ArtemisImageBuffer.restype = ctypes.c_void_p self._lib.ArtemisExposureTimeRemaining.restype = ctypes.c_float self._lib.ArtemisLastExposureDuration.restype = ctypes.c_float self._lib.ArtemisLastStartTime.restype = ctypes.c_char_p except Exception as e: log.error(f"Atik SDK load failed: {e}") Loading Loading @@ -120,7 +126,9 @@ class Camera(BaseDevice): def start(self, duration, frametype, datetime=None): h = self._check_connection() if not h: return # Using put internally for consistency self._last_exptime = duration self._last_frametype = frametype self._last_datetime = datetime is_dark = True if frametype in [0, 2, "Dark", "Bias"] else False self._lib.ArtemisSetDarkMode(h, is_dark) self._lib.ArtemisStartExposure(h, ctypes.c_float(duration)) Loading @@ -141,13 +149,57 @@ class Camera(BaseDevice): ctypes.byref(bx), ctypes.byref(by)) buf_ptr = self._lib.ArtemisImageBuffer(h) if buf_ptr: if not buf_ptr: return from pathlib import Path from ..config.constants import frame_type as _frame_type Path(filepath).parent.mkdir(parents=True, exist_ok=True) size = w.value * h_img.value buffer = (ctypes.c_uint16 * size).from_address(buf_ptr) data = np.frombuffer(buffer, dtype=np.uint16).reshape(h_img.value, w.value) fits.PrimaryHDU(data).writeto(filepath, overwrite=True) hdu = fits.PrimaryHDU(data) hdr = hdu.header hdr['INSTRUME'] = (self._props.Description.decode(), "Camera model") exptime = self._lib.ArtemisLastExposureDuration(h) if exptime == 0.0 and self._last_exptime is not None: exptime = self._last_exptime hdr['EXPTIME'] = (float(exptime), "[s] Exposure duration") start_time_bytes = self._lib.ArtemisLastStartTime(h) start_ms = self._lib.ArtemisLastStartTimeMilliseconds(h) if start_time_bytes: hdr['DATE-OBS'] = (f"{start_time_bytes.decode()}.{start_ms:03d}", "(UTC) Date the exposure was started") elif self._last_datetime is not None: hdr['DATE-OBS'] = (str(self._last_datetime), "(UTC) Date the exposure was started") ccd_temp = ctypes.c_int() self._lib.ArtemisTemperatureSensorInfo(h, 1, ctypes.byref(ccd_temp)) hdr['CCD-TEMP'] = (ccd_temp.value / 100.0, "[C] CCD temperature") flags, level, minl, maxl, setp = [ctypes.c_int() for _ in range(5)] self._lib.ArtemisCoolingInfo(h, ctypes.byref(flags), ctypes.byref(level), ctypes.byref(minl), ctypes.byref(maxl), ctypes.byref(setp)) hdr['SET-TEMP'] = (setp.value / 100.0, "[C] CCD setpoint temperature") hdr['XPIXSZ'] = (self._props.PixelMicronsX, "[um] Pixel X size") hdr['YPIXSZ'] = (self._props.PixelMicronsY, "[um] Pixel Y size") hdr['XBINNING'] = (bx.value, "X binning factor") hdr['YBINNING'] = (by.value, "Y binning factor") hdr['XORGSUBF'] = (self._subframe[0], "[px] Subframe X origin (unbinned)") hdr['YORGSUBF'] = (self._subframe[1], "[px] Subframe Y origin (unbinned)") ft = self._last_frametype hdr['IMAGETYP'] = (_frame_type.get(ft, str(ft)) if ft is not None else "", "Image type") hdu.writeto(filepath, overwrite=True) # --- Windowing Methods --- Loading