From 28f33d9b6213faa8ff88d131f2db3b0d6c88b91f Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Wed, 11 Feb 2026 17:20:35 +0300 Subject: [PATCH] add Toupcam support; fix some bugs --- CMakeLists.txt | 16 +- EXAMPLE_for_cameras/CMakeLists.txt | 15 + EXAMPLE_for_cameras/example.c | 458 +++++++++++++++++++++ HIKROBOT_cameras/CMakeLists.txt | 3 + TOUPCAM_cameras/CMakeLists.txt | 15 + TOUPCAM_cameras/toupcam.c | 639 +++++++++++++++++++++++++++++ ccdcapture.c | 2 +- ccdcapture.h | 6 +- ccdfunc.c | 108 ++--- locale/ru/messages.po | 142 +++---- locale/ru/ru.po | 142 +++---- 11 files changed, 1330 insertions(+), 216 deletions(-) create mode 100644 EXAMPLE_for_cameras/CMakeLists.txt create mode 100644 EXAMPLE_for_cameras/example.c create mode 100644 TOUPCAM_cameras/CMakeLists.txt create mode 100644 TOUPCAM_cameras/toupcam.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c419d8..7d2573c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,12 +17,13 @@ message("VER: ${VERSION}") option(DEBUG "Compile in debug mode" OFF) option(DUMMY "Dummy camera plugin" ON) option(IMAGEVIEW "Build with imageview module" ON) -option(ZWO "Add support of ZWO cameras" OFF) -option(FLI "Add support of FLI cameras" OFF) -option(BASLER "Add support of BASLER cameras" OFF) -option(HIKROBOT "Add support of HIKROBOT cameras" OFF) -option(FLYCAP "Add support of Grasshopper FlyCap cameras" OFF) -option(APOGEE "Add support of Apogee cameras" OFF) +option(ZWO "Add support for ZWO cameras" OFF) +option(FLI "Add support for FLI cameras" OFF) +option(BASLER "Add support for BASLER cameras" OFF) +option(HIKROBOT "Add support for HIKROBOT cameras" OFF) +option(FLYCAP "Add support for Grasshopper FlyCap cameras" OFF) +option(APOGEE "Add support for Apogee cameras" OFF) +option(TOUPCAM "Add support for ToupCam CMOS" OFF) option(EXAMPLES "Some examples" OFF) option(ASTAR "Artifical star plugin" OFF) @@ -109,6 +110,9 @@ endif() if(APOGEE) add_subdirectory(APOGEE_cameras) endif() +if(TOUPCAM) + add_subdirectory(TOUPCAM_cameras) +endif() if(EXAMPLES) add_subdirectory(examples) endif() diff --git a/EXAMPLE_for_cameras/CMakeLists.txt b/EXAMPLE_for_cameras/CMakeLists.txt new file mode 100644 index 0000000..01cdaa9 --- /dev/null +++ b/EXAMPLE_for_cameras/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20) +set(CCDLIB devexample) + +SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +find_package(PkgConfig REQUIRED) +pkg_check_modules(${CCDLIB} REQUIRED usefull_macros exmodule) + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) +add_library(${CCDLIB} SHARED ${SRC}) + +target_include_directories(${CCDLIB} PRIVATE ${${CCDLIB}_INCLUDE_DIRS} ..) +target_link_directories(${CCDLIB} PRIVATE ${${CCDLIB}_LIBRARY_DIRS}) + +target_link_libraries(${CCDLIB} ${${CCDLIB}_LIBRARIES} -fPIC) +install(TARGETS ${CCDLIB} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/EXAMPLE_for_cameras/example.c b/EXAMPLE_for_cameras/example.c new file mode 100644 index 0000000..f96de22 --- /dev/null +++ b/EXAMPLE_for_cameras/example.c @@ -0,0 +1,458 @@ +/* + * This file is part of the CCD_Capture project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ccdcapture.h" + +extern cc_Camera camera; +extern cc_Focuser focuser; +extern cc_Wheel wheel; + +/** + * @brief campoll - camera.pollcapture - polling of capture process status + * @param st (o) - status of capture process + * @param remain (o) - time remain (s) + * @return FALSE if error (exp aborted), TRUE while no errors + */ +static int campoll(cc_capture_status _U_ *st, float _U_ *remain){ + return FALSE; +} + +/** + * @brief startexp - camera.startexposition - start exp if can + * @return FALSE if failed + */ +static int startexp(){ + return FALSE; +} + +/** + * @brief camcapt - camera.capture - capture an image, struct `ima` should be prepared before + * @param ima (o) - captured image + * @return FALSE if failed or bad `ima` + */ +static int camcapt(cc_IMG _U_ *ima){ + return FALSE; +} + +/** + * @brief camsetbit - camera.setbitdepth + * @param b - bit depth, 1 - high (16 bit), 0 - low (8 or other bit) + * @return FALSE if failed + */ +static int camsetbit(int _U_ b){ + return FALSE; +} + +/** + * @brief camgetbp - camera.getbitpix - get bit depth in bits per pixel (8, 12, 16 etc) + * @param bp (o) - bits per pixel + * @return FALSE if failed + */ +static int camgetbp(uint8_t _U_ *bp){ + return FALSE; +} + +/** + * @brief camcancel - camera.cancel - cancel exposition + */ +static void camcancel(){ + ; +} + +/** + * @brief setdevno - camera.setDevNo - set active device number + * @param n - device no + * @return FALSE if no such device or failed + */ +static int setdevno(int _U_ n){ + return FALSE; +} + +/** + * @brief camsetbrig - camera.setbrightness - set `brightness` + * @param b - `brightness` value + * @return FALSE if failed or no such property + */ +static int camsetbrig(float _U_ b){ + return FALSE; +} + +/** + * @brief camgetbrig - camera.getbrightness - get `brightness` value + * @param b (o) - brightness + * @return FALSE if failed or no such property + */ +static int camgetbrig(float _U_ *b){ + return FALSE; +} + +/** + * @brief camsetexp - camera.setexp - set exposition time (s) + * @param t - time (s) + * @return FALSE if failed + */ +static int camsetexp(float _U_ t){ + return FALSE; +} + +/** + * @brief camsetgain - camera.setgain - set gain + * @param g - gain + * @return FALSE if gain is wrong or no such property + */ +static int camsetgain(float _U_ g){ + return FALSE; +} + +/** + * @brief camgetgain - camera.getgain - getter + * @param g (o) - gain + * @return FALSE if have no such property + */ +static int camgetgain(float _U_ *g){ + return FALSE; +} + +/** + * @brief camsett - camera.setT - set cold side temperature + * @param t - temperature (degC) + * @return FALSE if failed + */ +static int camsett(float _U_ t){ + return FALSE; +} + +/** + * @brief camgett - camera.getTcold - get cold side T + * @param t - temperature (degC) + * @return FALSE if failed or no such property + */ +static int camgettc(float _U_ *t){ + return FALSE; +} + +/** + * @brief camgett - camera.getThot - get hot side T + * @param t - temperature (degC) + * @return FALSE if failed or no such property + */ +static int camgetth(float _U_ *t){ + return FALSE; +} + +/** + * @brief camgett - camera.getTbody - get body T + * @param t - temperature (degC) + * @return FALSE if failed or no such property + */ +static int gettb(float _U_ *t){ + return FALSE; +} + +/** + * @brief camsetbin - camera.setbin - binning setter + * @param h, v - binning values (horiz/vert) + * @return FALSE if failed or can't change binning + */ +static int camsetbin(int _U_ h, int _U_ v){ + return FALSE; +} + +/** + * @brief camshutter - camera.shuttercmd - work with shutter + * @param s - new command for shutter (open/close etc) + * @return FALSE if failed or can't + */ +static int camshutter(cc_shutter_op _U_ s){ + return FALSE; +} + +/** + * @brief camsetgeom - camera.setgeometry - set geometry in UNBINNED coordinates + * @param f (i) - new geometry + * @return FALSE if can't change ROI or wrong geometry + */ +static int camsetgeom(cc_frameformat _U_ *f){ + return FALSE; +} + +/** + * @brief camgetnam - camera.getModelName - get model name + * @param n (io) - prepared string for name + * @param l - full length of n in bytes + * @return FALSE if can't + */ +static int camgetnam(char _U_ *n, int _U_ l){ + return FALSE; +} + +/** + * @brief camgmg - camera.getmaxgain - get max available gain + * @param mg (o) - max gain + * @return FALSE if can't change gain + */ +static int camgmg(float _U_ *mg){ + return FALSE; +} + +/** + * @brief camggl - camera.getgeomlimits - get limits of ROI changing + * @param max (o) - max ROI + * @param step (o) - step for ROI change + * @return + */ +static int camggl(cc_frameformat _U_ *max, cc_frameformat _U_ *step){ + return FALSE; +} + +/** + * @brief camgetbin - camera.getbin - binning getter + * @param binh (o), binv (o) - current binning + * @return FALSE if can't change binning + */ +static int camgetbin(int _U_ *binh, int _U_ *binv){ + return FALSE; +} + +/** + * @brief camgetio - camera.getio - get IO status + * @param io (o) - GPIO status + * @return FALSE if have no such property + */ +static int camgetio(int _U_ *io){ + return FALSE; +} + +/** + * @brief camfan - camera.setfanspeed - set fan speed + * @param spd - new speed + * @return FALSE if can't + */ +static int camfan(cc_fan_speed _U_ spd){ + return FALSE; +} + +/** + * @brief focsetpos - focuser.setAbsPos - set absolute position (in millimeters!!!) + * @param a - ==1 for async running + * @param n - new position + * @return FALSE if failed or bad values + */ +static int focsetpos(int _U_ a, float _U_ n){ + return FALSE; +} + +/** + * @brief fochome - focuser.home - go to homing position + * @param a - async flag + * @return FALSE if failed + */ +static int fochome(int _U_ a){ + return FALSE; +} + +/** + * @brief focgetnam - focuser.getModelName - get name + * @param n (o) - string for name + * @param l - its length + * @return FALSE if failed + */ +static int focgetnam(char _U_ *n, int _U_ l){ + return FALSE; +} + +/** + * @brief focpos - focuser.getPos - get current position + * @param p (o) - position + * @return FALSE if failed + */ +static int focpos(float _U_ *p){ + return FALSE; +} + +/** + * @brief focMp - focuser.getMaxPos - max position number + * @param p (o) - number + * @return FALSE if failed + */ +static int focMp(float _U_ *p){ + return FALSE; +} + +/** + * @brief focmp - focuser.getMinPos - min position number + * @param p (o) - position + * @return FALSE if failed + */ +static int focmp(float _U_ *p){ + return FALSE; +} + +/** + * @brief whlsetpos - wheel.setPos - set position + * @param n - new position + * @return FALSE if failed or bad position + */ +static int whlsetpos(int _U_ n){ + return FALSE; +} + +/** + * @brief whlgetpos - wheel.getPos - get current position + * @param n (o) - position + * @return FALSE if failed + */ +static int whlgetpos(int _U_ *n){ + return FALSE; +} + +/** + * @brief whlgmp - wheel.getMaxPos - get max position + * @param n (o) - position + * @return FALSE if failed + */ +static int whlgmp(int _U_ *n){ + return FALSE; +} + +/** + * @brief whlgetnam - whhel.getModelName - get string with name + * @param n (o) - string for name + * @param l - its length + * @return + */ +static int whlgetnam(char _U_ *n, int _U_ l){ + return FALSE; +} + +#if 0 +double sinPx, sinPy, sinmin; +// cmd, help, checker, pointer, min, max, type +static cc_parhandler_t handlers[] = { + {"px", "set/get sin period over X axis (pix)", NULL, (void*)&sinPx, (void*)&sinmin, NULL, CC_PAR_DOUBLE}, + {"py", "set/get sin period over Y axis (pix)", NULL, (void*)&sinPy, (void*)&sinmin, NULL, CC_PAR_DOUBLE}, + CC_PARHANDLER_END +}; +#endif + +/** + * @brief plugincmd - custom camera plugin command (get string as input, send string as output or NULL if failed) + * @param str + * @param buf + * @return + */ +static cc_hresult plugincmd(const char _U_ *str, cc_charbuff _U_ *buf){ + return CC_RESULT_FAIL; + //return cc_plugin_customcmd(str, handlers, buf); +} + +// stub for nonexistant properties +static int stub(){ + return FALSE; +} + +// stub for void nonexistant functions +static void vstub(){ + FNAME(); + return; +} + +// stub for nonexistant integer setters +static int istub(int _U_ N){ + return FALSE; +} + +/* + * Global objects: camera, focuser and wheel + */ +__attribute__ ((visibility("default"))) cc_Camera camera = { + .check = stub, + .Ndevices = 1, + .close = vstub, + .pollcapture = campoll, + .capture = camcapt, + .cancel = camcancel, + .startexposition = startexp, + .plugincmd = plugincmd, + // setters: + .setDevNo = setdevno, + .setbrightness = camsetbrig, + .setexp = camsetexp, + .setgain = camsetgain, + .setT = camsett, + .setbin = camsetbin, + .setnflushes = istub, + .shuttercmd = camshutter, + .confio = istub, + .setio = istub, + .setframetype = istub, + .setbitdepth = camsetbit, + .setfastspeed = istub, + .setgeometry = camsetgeom, + .setfanspeed = camfan, + // getters: + .getbitpix = camgetbp, + .getbrightness = camgetbrig, + .getModelName = camgetnam, + .getgain = camgetgain, + .getmaxgain = camgmg, + .getgeomlimits = camggl, + .getTcold = camgettc, + .getThot = camgetth, + .getTbody = gettb, + .getbin = camgetbin, + .getio = camgetio, + // these parameters could be filled after initialization + .pixX = 10., + .pixY = 10., + .field = (cc_frameformat){.h = 1024, .w = 1024, .xoff = 10, .yoff = 10}, + .array = (cc_frameformat){.h = 1050, .w = 1050, .xoff = 0, .yoff = 0}, + .geometry = {0}, +}; + +__attribute__ ((visibility("default"))) cc_Focuser focuser = { + .check = stub, + .Ndevices = 1, + .close = vstub, + // setters: + .setDevNo = setdevno, + .setAbsPos = focsetpos, + .home = fochome, + // getters: + .getModelName = focgetnam, + .getTbody = gettb, + .getPos = focpos, + .getMaxPos = focMp, + .getMinPos = focmp, +}; + +__attribute__ ((visibility("default"))) cc_Wheel wheel = { + .check = stub, + .Ndevices = 1, + .close = vstub, + // setters + .setDevNo = setdevno, + .setPos = whlsetpos, + // getters + .getModelName = whlgetnam, + .getTbody = gettb, + .getPos = whlgetpos, + .getMaxPos = whlgmp, +}; diff --git a/HIKROBOT_cameras/CMakeLists.txt b/HIKROBOT_cameras/CMakeLists.txt index 84e5f54..71fec0c 100644 --- a/HIKROBOT_cameras/CMakeLists.txt +++ b/HIKROBOT_cameras/CMakeLists.txt @@ -8,6 +8,9 @@ pkg_check_modules(${CCDLIB} REQUIRED mvs>=2.1 usefull_macros) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) add_library(${CCDLIB} SHARED ${SRC}) +# set c99 as mvs library have "typedef" for "bool" +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") + target_include_directories(${CCDLIB} PRIVATE ${${CCDLIB}_INCLUDE_DIRS} ..) target_link_directories(${CCDLIB} PRIVATE ${${CCDLIB}_LIBRARY_DIRS}) diff --git a/TOUPCAM_cameras/CMakeLists.txt b/TOUPCAM_cameras/CMakeLists.txt new file mode 100644 index 0000000..6eda3d5 --- /dev/null +++ b/TOUPCAM_cameras/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20) +set(CCDLIB devtoupcam) + +SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +find_package(PkgConfig REQUIRED) +pkg_check_modules(${CCDLIB} REQUIRED usefull_macros toupcam) + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) +add_library(${CCDLIB} SHARED ${SRC}) + +target_include_directories(${CCDLIB} PRIVATE ${${CCDLIB}_INCLUDE_DIRS} ..) +target_link_directories(${CCDLIB} PRIVATE ${${CCDLIB}_LIBRARY_DIRS}) + +target_link_libraries(${CCDLIB} ${${CCDLIB}_LIBRARIES} -fPIC) +install(TARGETS ${CCDLIB} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/TOUPCAM_cameras/toupcam.c b/TOUPCAM_cameras/toupcam.c new file mode 100644 index 0000000..7819866 --- /dev/null +++ b/TOUPCAM_cameras/toupcam.c @@ -0,0 +1,639 @@ +/* + * This file is part of the CCD_Capture project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "ccdcapture.h" + +extern cc_Camera camera; +extern cc_Focuser focuser; +extern cc_Wheel wheel; + +// flags for image processing +typedef enum{ + IM_SLEEP, + IM_STARTED, + IM_READY, + IM_ERROR +} imstate_t; + +// devices +static ToupcamDeviceV2 g_dev[TOUPCAM_MAX] = {0}; +static struct{ + ToupcamDeviceV2* dev; + HToupcam hcam; + unsigned long long flags; + void* data; + imstate_t state; +} toupcam = {0}; + +static int camgetbp(uint8_t *bp); + +// exptime and starting of exposition +static double exptime = 0., starttime = 0.; + +#define TCHECK() do{if(!toupcam.hcam) return FALSE;}while(0) + +/** + * @brief camcancel - camera.cancel - cancel exposition + */ +static void camcancel(){ + if(!toupcam.hcam) return; + Toupcam_Trigger(toupcam.hcam, 0); // stop triggering + Toupcam_Stop(toupcam.hcam); + toupcam.state = IM_SLEEP; +} + +// close camera device +static void camclose(){ + camcancel(); + if(toupcam.hcam){ + DBG("Close camera"); + Toupcam_Close(toupcam.hcam); + toupcam.hcam = NULL; + } + if(toupcam.data){ + DBG("Free image data"); + free(toupcam.data); + toupcam.data = NULL; + } +} + +/** + * @brief initcam - init camera + * @return FALSE if failed + */ +static int initcam(){ + camclose(); + unsigned N = Toupcam_EnumV2(g_dev); + if(0 == N){ + DBG("Found 0 toupcams"); + return FALSE; + } + camera.Ndevices = (int) N; + return TRUE; +} + +// callback of image ready event +static void EventCallback(unsigned nEvent, void _U_ *pCallbackCtx){ + DBG("CALLBACK with evt %d", nEvent); + if(!toupcam.hcam || !toupcam.data){ DBG("NO data!"); return; } + if(nEvent != TOUPCAM_EVENT_IMAGE){ DBG("Not image event"); return; } + ToupcamFrameInfoV4 info = {0}; + if(Toupcam_PullImageV4(toupcam.hcam, toupcam.data, 0, 0, 0, &info) < 0){ + DBG("Error pulling image"); + toupcam.state = IM_ERROR; + }else{ + DBG("Image ready!"); + toupcam.state = IM_READY; + camera.geometry.h = info.v3.height; + camera.geometry.w = info.v3.width; + } +} + +/** + * @brief setdevno - camera.setDevNo - set active device number + * @param n - device no + * @return FALSE if no such device or failed + */ +static int setdevno(int n){ + if(n < 0 || n >= camera.Ndevices) return FALSE; + camclose(); // close if was opened + toupcam.dev = &g_dev[n]; + toupcam.hcam = Toupcam_Open(g_dev[n].id); + if(!toupcam.hcam){ + DBG("Can't open %dth camera", n); + return FALSE; + } + DBG("Opened %s", toupcam.dev->displayname); + DBG("Clear ROI"); + Toupcam_put_Roi(toupcam.hcam, 0, 0, 0, 0); // clear ROI + // now fill camera geometry + DBG("Get geometry"); + Toupcam_get_Size(toupcam.hcam, &camera.geometry.w, &camera.geometry.h); + DBG("size (wxh): %dx%d", camera.geometry.w, camera.geometry.h); + unsigned int xoff, yoff, h, w; + DBG("Get ROI"); + Toupcam_get_Roi(toupcam.hcam, &xoff, &yoff, &w, &h); + DBG("off (x/y): %d/%d; wxh: %dx%d", xoff, yoff, w, h); + camera.array.xoff = camera.field.xoff = xoff; + camera.array.yoff = camera.field.yoff = yoff; + camera.array.w = camera.field.w = w; + camera.array.h = camera.field.h = h; + DBG("Get pixel size"); + Toupcam_get_PixelSize(toupcam.hcam, 0, &camera.pixX, &camera.pixY); + DBG("pixsize (x/y): %g/%g", camera.pixX, camera.pixY); + toupcam.flags = Toupcam_query_Model(toupcam.hcam)->flag; + DBG("flags: 0x%llx", toupcam.flags); + DBG("Allocate data (%d bytes)", 2 * camera.array.w * camera.array.h); + toupcam.data = calloc(camera.array.w * camera.array.h, 2); +#define OPT(opt, val, comment) do{DBG(comment); if(Toupcam_put_Option(toupcam.hcam, opt, val) < 0){ DBG("Can't put this option"); }}while(0) + OPT(TOUPCAM_OPTION_TRIGGER, 1, "Software/simulated trigger mode"); + //OPT(TOUPCAM_OPTION_DFC, 0xff0000ff , "Enable dark field correction"); + //OPT(TOUPCAM_OPTION_FFC, 0xff0000ff, "Enable flatfield correction"); + OPT(TOUPCAM_OPTION_RAW, 1, "Put to RAW mode"); +#undef OPT + toupcam.state = IM_SLEEP; + return TRUE; +} + +/** + * @brief campoll - camera.pollcapture - polling of capture process status + * @param st (o) - status of capture process + * @param remain (o) - time remain (s) + * @return FALSE if error (exp aborted), TRUE while no errors + */ +static int campoll(cc_capture_status *st, float *remain){ + TCHECK(); + cc_capture_status curst; + double tremain = 0.f; + int ret = FALSE; + switch(toupcam.state){ + case IM_SLEEP: + curst = CAPTURE_NO; + break; + case IM_ERROR: + curst = CAPTURE_ABORTED; + break; + case IM_READY: + curst = CAPTURE_READY; + ret = TRUE; + break; + default: // IM_PROCESS + curst = CAPTURE_PROCESS; + //DBG("exptime: %g, d-s: %g", exptime, sl_dtime() - starttime); + tremain = exptime - (sl_dtime() - starttime); + if(tremain < -2.0) curst = CAPTURE_ABORTED; + else{ + if(tremain < 0.) tremain = 0.; + ret = TRUE; + } + } + //DBG("curst: %d, tremain: %g", curst, tremain); + if(st) *st = curst; + if(remain) *remain = (float)tremain; + return ret; +} + +/** + * @brief startexp - camera.startexposition - start exp if can + * @return FALSE if failed + */ +static int startexp(){ + TCHECK(); + if(toupcam.state == IM_SLEEP){ + if(Toupcam_StartPullModeWithCallback(toupcam.hcam, EventCallback, NULL) < 0){ + WARNX("Can't run PullMode with Callback!"); + return FALSE; + } + } + if(Toupcam_Trigger(toupcam.hcam, 1) < 0) return FALSE; + toupcam.state = IM_STARTED; + starttime = sl_dtime(); + return TRUE; +} + +/** + * @brief camcapt - camera.capture - capture an image, struct `ima` should be prepared before + * @param ima (o) - captured image + * @return FALSE if failed or bad `ima` + */ +static int camcapt(cc_IMG *ima){ + TCHECK(); + if(!ima || !ima->data || !toupcam.data) return FALSE; + uint8_t bp; + if(!camgetbp(&bp)) bp = 16; + size_t fullsz = camera.geometry.h * camera.geometry.w * (int)((bp+7)/8); + memcpy(ima->data, toupcam.data, fullsz); + ima->bitpix = bp; + ima->h = camera.geometry.h; + ima->w = camera.geometry.w; + ima->bytelen = fullsz; + return TRUE; +} + +/** + * @brief camsetbit - camera.setbitdepth + * @param b - bit depth, 1 - high (16 bit), 0 - low (8 or other bit) + * @return FALSE if failed + */ +static int camsetbit(int b){ + TCHECK(); + DBG("set bitdepth %d", b); + if(Toupcam_put_Option(toupcam.hcam, TOUPCAM_OPTION_BITDEPTH, b) < 0) return FALSE; + int opt = (b) ? TOUPCAM_PIXELFORMAT_RAW16 : TOUPCAM_PIXELFORMAT_RAW8; + DBG("set pixel format %d", opt); + if(Toupcam_put_Option(toupcam.hcam, TOUPCAM_OPTION_PIXEL_FORMAT, opt) < 0) return FALSE; + return TRUE; +} + +/** + * @brief camgetbp - camera.getbitpix - get bit depth in bits per pixel (8, 12, 16 etc) + * @param bp (o) - bits per pixel + * @return FALSE if failed + */ +static int camgetbp(uint8_t *bp){ + TCHECK(); + int b; + DBG("Get bitdepth"); + if(Toupcam_get_Option(toupcam.hcam, TOUPCAM_OPTION_BITDEPTH, &b) < 0) return FALSE; + DBG("bitdepth=%d", b); + if(bp){ + if(b == 0) *bp = 8; + else{ + DBG("Get pixformat"); + if(Toupcam_get_Option(toupcam.hcam, TOUPCAM_OPTION_PIXEL_FORMAT, &b) < 0) return FALSE; + DBG("pixformat=%d", b); + *bp = 8 + b*2; + } + } + return TRUE; +} + +/** + * @brief camsetbrig - camera.setbrightness - set `brightness` + * @param b - `brightness` value + * @return FALSE if failed or no such property + */ +static int camsetbrig(float b){ + TCHECK(); + if(b < 0.f) return FALSE; + int br = (int) b; + DBG("Try to set brightness to %d", br); + if(Toupcam_put_Brightness(toupcam.hcam, br)) return FALSE; + DBG("OK"); + return TRUE; +} + +/** + * @brief camgetbrig - camera.getbrightness - get `brightness` value + * @param b (o) - brightness + * @return FALSE if failed or no such property + */ +static int camgetbrig(float *b){ + TCHECK(); + int br; + DBG("get brightness"); + if(Toupcam_get_Brightness(toupcam.hcam, &br) < 0) return FALSE; + DBG("brightness=%d", br); + if(b) *b = (float) br; + return FALSE; +} + +/** + * @brief camsetexp - camera.setexp - set exposition time (s) + * @param t - time (s) + * @return FALSE if failed + */ +static int camsetexp(float t){ + TCHECK(); + if(t < FLT_EPSILON) return FALSE; + unsigned int microseconds = (unsigned)(t * 1e6f); + DBG("Set exptime to %dus", microseconds); + if(Toupcam_put_ExpoTime(toupcam.hcam, microseconds) < 0) return FALSE; + DBG("OK"); + exptime = (double) t; + return TRUE; +} + +/** + * @brief camsetgain - camera.setgain - set gain + * @param g - gain + * @return FALSE if gain is wrong or no such property + */ +static int camsetgain(float g){ + TCHECK(); + unsigned short G = (unsigned short)(100.f * g); + if(Toupcam_put_ExpoAGain(toupcam.hcam, G) < 0){ + unsigned short gmin, gmax, gdef; + if(Toupcam_get_ExpoAGainRange(toupcam.hcam, &gmin, &gmax, &gdef) >= 0) + WARNX("Gain out of range; min: %g, max: %g, default: %g", + (float)gmin/100.f, (float)gmax/100.f, (float)gdef/100.f); + return FALSE; + } + DBG("GAIN is %d", G); + return TRUE; +} + +/** + * @brief camgetgain - camera.getgain - getter + * @param g (o) - gain + * @return FALSE if have no such property + */ +static int camgetgain(float *g){ + TCHECK(); + unsigned short G; + if(Toupcam_get_ExpoAGain(toupcam.hcam, &G) < 0) return FALSE; + if(g) *g = (float)G / 100.f; + return TRUE; +} + +/** + * @brief camsett - camera.setT - set cold side temperature + * @param t - temperature (degC) + * @return FALSE if failed + */ +static int camsett(float t){ + TCHECK(); + if(!(toupcam.flags & TOUPCAM_FLAG_TEC)) return FALSE; // cannot set temperature + if(toupcam.flags & TOUPCAM_FLAG_TEC_ONOFF){ + int onoff = (t < 20.f) ? 1 : 0; + if(Toupcam_put_Option(toupcam.hcam, TOUPCAM_OPTION_TEC, onoff) < 0) return FALSE; + if(!onoff) return TRUE; // just turn off TEC if user wants >= 20degC + } + short T = (short) t * 10.f; + DBG("Try to set T=%g", t); + if(Toupcam_put_Temperature(toupcam.hcam, T) < 0) return FALSE; + DBG("OK"); + return TRUE; +} + +/** + * @brief camgett - camera.getTcold - get cold side T + * @param t - temperature (degC) + * @return FALSE if failed or no such property + */ +static int camgettc(float *t){ + TCHECK(); + if(!(toupcam.flags & TOUPCAM_FLAG_GETTEMPERATURE)) return FALSE; // cannot get T + short T; + DBG("Try to get T"); + if(Toupcam_get_Temperature(toupcam.hcam, &T) < 0) return FALSE; + DBG("got %u", T); + if(t) *t = ((float)T) / 10.f; + return TRUE; +} + +/** + * @brief camgett - camera.getThot - get hot side T + * @param t - temperature (degC) + * @return FALSE if failed or no such property + */ +static int camgetth(float _U_ *t){ + TCHECK(); + return FALSE; +} + +/** + * @brief camgett - camera.getTbody - get body T + * @param t - temperature (degC) + * @return FALSE if failed or no such property + */ +static int gettb(float _U_ *t){ + TCHECK(); + return FALSE; +} + +/** + * @brief camsetbin - camera.setbin - binning setter + * @param h, v - binning values (horiz/vert) + * @return FALSE if failed or can't change binning + */ +static int camsetbin(int h, int v){ + TCHECK(); + if(h != v) return FALSE; + DBG("Try to set binning %d/%d", h,v); + if(Toupcam_put_Option(toupcam.hcam, TOUPCAM_OPTION_BINNING, h) < 0) return FALSE; + DBG("OK"); + return TRUE; +} + +/** + * @brief camgetbin - camera.getbin - binning getter + * @param binh (o), binv (o) - current binning + * @return FALSE if can't change binning + */ +static int camgetbin(int *binh, int *binv){ + TCHECK(); + int bin; + DBG("Get binning"); + if(Toupcam_get_Option(toupcam.hcam, TOUPCAM_OPTION_BINNING, &bin) < 0) return FALSE; + DBG("Got: %d", bin); + if(binh) *binh = bin; + if(binv) *binv = bin; + return TRUE; +} + +/** + * @brief camshutter - camera.shuttercmd - work with shutter + * @param s - new command for shutter (open/close etc) + * @return FALSE if failed or can't + */ +static int camshutter(cc_shutter_op _U_ s){ + TCHECK(); + if(!(toupcam.flags & TOUPCAM_FLAG_GLOBALSHUTTER)) return FALSE; + return FALSE; +} + +/** + * @brief camsetgeom - camera.setgeometry - set geometry in UNBINNED coordinates + * @param f (i) - new geometry + * @return FALSE if can't change ROI or wrong geometry + */ +static int camsetgeom(cc_frameformat *f){ + TCHECK(); + if(Toupcam_put_Roi(toupcam.hcam, (unsigned) f->xoff, (unsigned) f->yoff, (unsigned) f->w, (unsigned) f->h) < 0) return FALSE; + camera.geometry = *f; + return TRUE; +} + +/** + * @brief camgetnam - camera.getModelName - get model name + * @param n (io) - prepared string for name + * @param l - full length of n in bytes + * @return FALSE if can't + */ +static int camgetnam(char *n, int l){ + TCHECK(); + if(!toupcam.dev) return FALSE; + DBG("name: %s, strncpy to %d buf", toupcam.dev->displayname, l); + strncpy(n, toupcam.dev->displayname, l); + return FALSE; +} + +/** + * @brief camgmg - camera.getmaxgain - get max available gain + * @param mg (o) - max gain + * @return FALSE if can't change gain + */ +static int camgmg(float _U_ *mg){ + TCHECK(); + return FALSE; +} + +/** + * @brief camggl - camera.getgeomlimits - get limits of ROI changing + * @param max (o) - max ROI + * @param step (o) - step for ROI change + * @return + */ +static int camggl(cc_frameformat _U_ *max, cc_frameformat _U_ *step){ + TCHECK(); + return FALSE; +} + +/** + * @brief camgetio - camera.getio - get IO status + * @param io (o) - GPIO status + * @return FALSE if have no such property + */ +static int camgetio(int _U_ *io){ + TCHECK(); + return FALSE; +} + +/** + * @brief camfan - camera.setfanspeed - set fan speed + * @param spd - new speed + * @return FALSE if can't + */ +static int camfan(cc_fan_speed spd){ + TCHECK(); + if(!(toupcam.flags & TOUPCAM_FLAG_FAN)) return FALSE; // don't have a fan + DBG("Set fan to %d", spd); + if(Toupcam_put_Option(toupcam.hcam, TOUPCAM_OPTION_FAN, (int)spd) < 0){ DBG("Can't put this option"); } + return FALSE; +} + +static cc_hresult setopt(const char *str, cc_charbuff *ans){ + if(!str || !toupcam.hcam) return CC_RESULT_FAIL; + char key[256], *kptr = key; + snprintf(key, 255, "%s", str); + char *val = cc_get_keyval(&kptr); + if(!kptr || !val || strcmp(kptr, "opt")) return CC_RESULT_BADKEY; + snprintf(key, 255, "%s", val); // now this is our opt[=val] + kptr = key; val = cc_get_keyval(&kptr); + int result = -1, par; + int o; + if(!sl_str2i(&o, kptr)){ + cc_charbufput(ans, "Wrong integer: ", 15); + cc_charbufaddline(ans, kptr); + } + DBG("optD: %u", o); + if(val){ // setter + par = atoi(val); + result = Toupcam_put_Option(toupcam.hcam, (unsigned) o, par); + }else{ // getter + result = Toupcam_get_Option(toupcam.hcam, (unsigned) o, &par); + if(result >= 0){ + snprintf(key, 255, "Option %d have value %d", o, par); + cc_charbufaddline(ans, key); + } + } + if(result < 0 ) return CC_RESULT_FAIL; + return CC_RESULT_OK; +} + +static cc_hresult getpf(const char *str, cc_charbuff *ans){ + if(!str || !toupcam.hcam) return CC_RESULT_FAIL; + int N; + if(Toupcam_get_PixelFormatSupport(toupcam.hcam, -1, &N) < 0) return CC_RESULT_FAIL; + cc_charbufaddline(ans, "Supported formats:"); + for(int f = 0; f < N; ++f){ + int pf; + if(Toupcam_get_PixelFormatSupport(toupcam.hcam, f, &pf) < 0) continue; + cc_charbufaddline(ans, Toupcam_get_PixelFormatName(pf)); + } + return CC_RESULT_SILENCE; +} + +// cmd, help, checker, pointer, min, max, type +static cc_parhandler_t handlers[] = { + {"opt", "set/get given option, like opt=0x08=1 (TOUPCAM_OPTION_TEC ON) or opt=0x08 (check)", setopt, NULL, NULL, NULL, 0}, + {"pixfmt", "get list of supported pixel formats", getpf, NULL, NULL, NULL, 0}, + CC_PARHANDLER_END +}; + +/** + * @brief plugincmd - custom camera plugin command (get string as input, send string as output or NULL if failed) + * @param str + * @param buf + * @return + */ +static cc_hresult plugincmd(const char _U_ *str, cc_charbuff _U_ *buf){ + return cc_plugin_customcmd(str, handlers, buf); +} + +#if 0 +// stub for nonexistant properties +static int stub(){ + return FALSE; +} + +// stub for void nonexistant functions +static void vstub(){ + FNAME(); + return; +} +#endif +// stub for nonexistant integer setters +static int istub(int _U_ N){ + return FALSE; +} + +/* + * Global objects: camera, focuser and wheel + */ +__attribute__ ((visibility("default"))) cc_Camera camera = { + .check = initcam, + .Ndevices = 0, + .close = camclose, + .pollcapture = campoll, + .capture = camcapt, + .cancel = camcancel, + .startexposition = startexp, + .plugincmd = plugincmd, + // setters: + .setDevNo = setdevno, + .setbrightness = camsetbrig, + .setexp = camsetexp, + .setgain = camsetgain, + .setT = camsett, + .setbin = camsetbin, + .setnflushes = istub, + .shuttercmd = camshutter, + .confio = istub, + .setio = istub, + .setframetype = istub, + .setbitdepth = camsetbit, + .setfastspeed = istub, + .setgeometry = camsetgeom, + .setfanspeed = camfan, + // getters: + .getbitpix = camgetbp, + .getbrightness = camgetbrig, + .getModelName = camgetnam, + .getgain = camgetgain, + .getmaxgain = camgmg, + .getgeomlimits = camggl, + .getTcold = camgettc, + .getThot = camgetth, + .getTbody = gettb, + .getbin = camgetbin, + .getio = camgetio, + // these parameters could be filled after initialization + .pixX = 10., + .pixY = 10., + .field = (cc_frameformat){.h = 1024, .w = 1024, .xoff = 10, .yoff = 10}, + .array = (cc_frameformat){.h = 1050, .w = 1050, .xoff = 0, .yoff = 0}, + .geometry = {0}, +}; + diff --git a/ccdcapture.c b/ccdcapture.c index 3372301..58ce3d7 100644 --- a/ccdcapture.c +++ b/ccdcapture.c @@ -410,7 +410,7 @@ void cc_charbufclr(cc_charbuff *buf){ // put `l` bytes of `s` to b->buf and add terminated zero void cc_charbufput(cc_charbuff *b, const char *s, size_t l){ if(!cc_charbuftest(b, l+1)) return; - DBG("add %zd bytes to buff", l); + //DBG("add %zd bytes to buff", l); memcpy(b->buf + b->buflen, s, l); b->buflen += l; b->buf[b->buflen] = 0; diff --git a/ccdcapture.h b/ccdcapture.h index ee351e1..e92253c 100644 --- a/ccdcapture.h +++ b/ccdcapture.h @@ -143,9 +143,9 @@ typedef struct{ int (*getio)(int *s); // get IO-port state cc_hresult (*plugincmd)(const char *str, cc_charbuff *ans); // custom camera plugin command (get string as input, send string as output or NULL if failed) float pixX, pixY; // pixel size in um - cc_frameformat field; // max field of view (full CCD field without overscans) - cc_frameformat array; // array format (with overscans) - cc_frameformat geometry; // current geometry settings (as in setgeometry) + cc_frameformat field; // max field of view (full CCD field without overscans) + cc_frameformat array; // array format (with overscans) + cc_frameformat geometry; // current geometry settings (as in setgeometry) } cc_Camera; // focuser diff --git a/ccdfunc.c b/ccdfunc.c index 5a7a7de..6cf5dad 100644 --- a/ccdfunc.c +++ b/ccdfunc.c @@ -140,8 +140,9 @@ do{ int status = 0, kt = 0; \ if(camera->getbrightness && camera->getbrightness(&tmpf)) FORMFLT("CAMBRIGH", tmpf, "CMOS brightness value"); - snprintf(templ, 2*FLEN_CARD, "TIMESTAM = %.3f / Time of acquisition end (UNIX)", img->timestamp); + snprintf(templ, 2*FLEN_CARD, "TIMESTAM = %.6f / Time of acquisition end (UNIX)", img->timestamp); FORMKW(templ); + FORMINT("IMSEQNO", (int)img->imnumber, "Number of image in full sequence"); // BINNING / Binning snprintf(templ, FLEN_CARD, "BINNING = '%d x %d' / Binning (hbin x vbin)", GP->hbin, GP->vbin); FORMKW(templ); @@ -285,64 +286,41 @@ static void stat8(cc_IMG *image){ size_t size = image->w * image->h; uint8_t max = 0, min = UINT8_MAX; uint8_t *idata = (uint8_t*)image->data; -#pragma omp parallel -{ - uint8_t maxpriv = 0, minpriv = UINT8_MAX; - double sumpriv = 0., sum2priv = 0.; - #pragma omp for nowait +#pragma omp parallel for reduction(+:sum, sum2) reduction(max:max) reduction(min:min) for(size_t i = 0; i < size; ++i){ uint8_t val = idata[i]; - float pv = (float) val; - sum += pv; - sum2 += (pv * pv); - if(max < val) max = val; - if(min > val) min = val; - } - #pragma omp critical - { - if(max < maxpriv) max = maxpriv; - if(min > minpriv) min = minpriv; - sum += sumpriv; - sum2 += sum2priv; + double pv = (double) val; + sum += pv; + sum2 += pv * pv; + if (val > max) max = val; + if (val < min) min = val; } + double sz = (double) size; + image->avr = sum / sz; + image->std = sqrt(fabs(sum2 / sz - image->avr * image->avr)); + image->max = max; + image->min = min; } - double sz = (float)size; - double avr = sum/sz; - image->avr = avr; - image->std = sqrt(fabs(sum2/sz - avr*avr)); - image->max = max; image->min = min; -} -static void stat16(cc_IMG *image){ - double sum = 0., sum2 = 0.; + +static void stat16(cc_IMG *image) { size_t size = image->w * image->h; + uint16_t *idata = (uint16_t*) image->data; + double sum = 0.0, sum2 = 0.0; uint16_t max = 0, min = UINT16_MAX; - uint16_t *idata = (uint16_t*)image->data; -#pragma omp parallel -{ - uint16_t maxpriv = 0, minpriv = UINT16_MAX; - double sumpriv = 0., sum2priv = 0.; - #pragma omp for nowait +#pragma omp parallel for reduction(+:sum, sum2) reduction(max:max) reduction(min:min) for(size_t i = 0; i < size; ++i){ uint16_t val = idata[i]; - float pv = (float) val; - sum += pv; - sum2 += (pv * pv); - if(max < val) max = val; - if(min > val) min = val; + double pv = (double) val; + sum += pv; + sum2 += pv * pv; + if (val > max) max = val; + if (val < min) min = val; } - #pragma omp critical - { - if(max < maxpriv) max = maxpriv; - if(min > minpriv) min = minpriv; - sum += sumpriv; - sum2 += sum2priv; - } -} - double sz = (float)size; - double avr = sum/sz; - image->avr = avr; - image->std = sqrt(fabs(sum2/sz - avr*avr)); - image->max = max; image->min = min; + double sz = (double) size; + image->avr = sum / sz; + image->std = sqrt(fabs(sum2 / sz - image->avr * image->avr)); + image->max = max; + image->min = min; } @@ -545,8 +523,8 @@ static cc_capture_status capt(){ if(camera->getTbody && camera->getTbody(&tmpf)) verbose(1, "BODYTEMP=%.1f", tmpf); } if(tremain > 6.) sleep(5); - else if(tremain > 0.9) sleep((int)(tremain+0.99)); - else usleep((int)(1e6*tremain) + 100000); + else if(tremain > 0.999999) sleep((int)(tremain+1e-6)); + else usleep((int)(1e6*tremain)); if(!camera) return CAPTURE_ABORTED; } DBG("Poll ends with %d", cs); @@ -562,7 +540,7 @@ cc_Camera *startCCD(){ if(!(camera = open_camera(plugin))) return NULL; } if(!camera->check()){ - verbose(3, _("No cameras found")); + WARNX(_("No cameras found")); LOGWARN(_("No cameras found")); return NULL; } @@ -579,15 +557,16 @@ void closecam(){ // make base settings; return TRUE if all OK int prepare_ccds(){ FNAME(); + char buf[BUFSIZ]; int rtn = FALSE; if(!startCCD()) return FALSE; if(GP->listdevices){ if(!camera->getModelName) WARNX(_("Camera plugin have no model name getter")); else for(int i = 0; i < camera->Ndevices; ++i){ if(camera->setDevNo && !camera->setDevNo(i)) continue; - char modname[256]; - camera->getModelName(modname, 255); - printf("Found camera #%d: %s\n", i, modname); + // if camera have no setDevNo function, it could have getModelName + camera->getModelName(buf, BUFSIZ-1); + printf("Found camera #%d: %s\n", i, buf); } } int num = GP->camdevno; @@ -607,9 +586,9 @@ int prepare_ccds(){ else{ char **p = GP->plugincmd; cc_charbuff *b = cc_charbufnew(); - DBG("got %s", *p); int stop = FALSE; while(p && *p){ + DBG("got %s", *p); cc_charbufclr(b); cc_hresult r = camera->plugincmd(*p, b); if(r == CC_RESULT_OK || r == CC_RESULT_SILENCE) green("Command '%s'", *p); @@ -636,7 +615,6 @@ int prepare_ccds(){ } } int x0,x1, y0,y1; - char buf[BUFSIZ]; if(camera->getModelName && camera->getModelName(buf, BUFSIZ)) verbose(2, _("Camera model: %s"), buf); verbose(2, _("Pixel size: %g x %g"), camera->pixX, camera->pixY); @@ -682,7 +660,7 @@ int prepare_ccds(){ if(GP->setio > -1){ verbose(1, _("Try to write %d to I/O port"), GP->setio); if(!camera->setio || !camera->setio(GP->setio)) - WARNX(_("Can't set IOport")); + ERRX(_("Can't set IOport")); } if(GP->exptime < 0.) goto retn; if(!isnan(GP->gain)){ @@ -690,7 +668,7 @@ int prepare_ccds(){ if(camera->setgain && camera->setgain(GP->gain)){ if(camera->getgain) camera->getgain(&GP->gain); verbose(1, _("Set gain to %g"), GP->gain); - }else WARNX(_("Can't set gain to %g"), GP->gain); + }else ERRX(_("Can't set gain to %g"), GP->gain); } if(!isnan(GP->brightness)){ if(camera->setbrightness && camera->setbrightness(GP->brightness)){ @@ -702,7 +680,7 @@ int prepare_ccds(){ if(GP->hbin < 1) GP->hbin = 1; if(GP->vbin < 1) GP->vbin = 1; if(!camera->setbin || !camera->setbin(GP->hbin, GP->vbin)){ - WARNX(_("Can't set binning %dx%d"), GP->hbin, GP->vbin); + ERRX(_("Can't set binning %dx%d"), GP->hbin, GP->vbin); if(camera->getbin) camera->getbin(&GP->hbin, &GP->vbin); } if(GP->X0 < 0) GP->X0 = x0; // default values @@ -714,7 +692,7 @@ int prepare_ccds(){ DBG("x1/x0: %d/%d", GP->X1, GP->X0); cc_frameformat fmt = {.w = GP->X1 - GP->X0, .h = GP->Y1 - GP->Y0, .xoff = GP->X0, .yoff = GP->Y0}; if(!camera->setgeometry || !camera->setgeometry(&fmt)) - WARNX(_("Can't set given geometry")); + ERRX(_("Can't set given geometry")); verbose(3, "Geometry: off=%d/%d, wh=%d/%d", fmt.xoff, fmt.yoff, fmt.w, fmt.h); if(GP->nflushes > 0){ if(!camera->setnflushes || !camera->setnflushes(GP->nflushes)) @@ -723,7 +701,7 @@ int prepare_ccds(){ } if(!camera->setexp) ERRX(_("Camera plugin have no exposition setter")); if(!camera->setexp(GP->exptime)) - WARNX(_("Can't set exposure time to %f seconds"), GP->exptime); + ERRX(_("Can't set exposure time to %f seconds"), GP->exptime); tmpi = (GP->dark) ? 0 : 1; if(!camera->setframetype || !camera->setframetype(tmpi)) WARNX(_("Can't change frame type")); @@ -758,8 +736,8 @@ DBG("w=%d, h=%d", raw_width, raw_height); cc_IMG ima = {.data = img, .w = raw_width, .h = raw_height}; if(GP->nframes < 1) GP->nframes = 1; for(int j = 0; j < GP->nframes; ++j){ - TIMESTAMP("Start next cycle"); TIMEINIT(); + TIMESTAMP("Start next cycle"); verbose(1, _("Capture frame %d"), j); if(!camera->startexposition) ERRX(_("Camera plugin have no function `start exposition`")); if(!camera->startexposition()){ @@ -778,6 +756,8 @@ DBG("w=%d, h=%d", raw_width, raw_height); WARNX(_("Can't grab image")); break; } + ima.timestamp = sl_dtime(); + ++ima.imnumber; ima.gotstat = 0; TIMESTAMP("Calc stat"); calculate_stat(&ima); diff --git a/locale/ru/messages.po b/locale/ru/messages.po index 8dd5f5a..17ba715 100644 --- a/locale/ru/messages.po +++ b/locale/ru/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-04-16 09:25+0300\n" +"POT-Creation-Date: 2026-02-11 17:12+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -269,315 +269,315 @@ msgstr "" msgid "Display image in OpenGL window" msgstr "" -#: ccdfunc.c:197 +#: ccdfunc.c:198 msgid "Camera device unknown" msgstr "" -#: ccdfunc.c:220 +#: ccdfunc.c:221 #, c-format msgid "Can't save file with prefix %s" msgstr "" -#: ccdfunc.c:268 +#: ccdfunc.c:269 #, c-format msgid "File saved as '%s'" msgstr "" -#: ccdfunc.c:277 +#: ccdfunc.c:278 msgid "Error saving file" msgstr "" -#: ccdfunc.c:355 +#: ccdfunc.c:333 #, c-format msgid "Image stat:\n" msgstr "" -#: ccdfunc.c:364 +#: ccdfunc.c:342 msgid "Focuser device not pointed" msgstr "" -#: ccdfunc.c:371 +#: ccdfunc.c:349 msgid "No focusers found" msgstr "" -#: ccdfunc.c:402 +#: ccdfunc.c:379 #, c-format msgid "Found %d focusers, you point number %d" msgstr "" -#: ccdfunc.c:406 +#: ccdfunc.c:383 msgid "Can't set active focuser number" msgstr "" -#: ccdfunc.c:420 +#: ccdfunc.c:397 msgid "Can't get focuser limit positions" msgstr "" -#: ccdfunc.c:427 +#: ccdfunc.c:404 msgid "Can't get current focuser position" msgstr "" -#: ccdfunc.c:441 +#: ccdfunc.c:418 #, c-format msgid "Can't set position %g: out of limits [%g, %g]" msgstr "" -#: ccdfunc.c:445 +#: ccdfunc.c:422 msgid "Can't home focuser" msgstr "" -#: ccdfunc.c:447 +#: ccdfunc.c:424 #, c-format msgid "Can't set position %g" msgstr "" -#: ccdfunc.c:455 +#: ccdfunc.c:432 msgid "Wheel device not pointed" msgstr "" -#: ccdfunc.c:462 +#: ccdfunc.c:439 msgid "No wheels found" msgstr "" -#: ccdfunc.c:493 +#: ccdfunc.c:469 #, c-format msgid "Found %d wheels, you point number %d" msgstr "" -#: ccdfunc.c:497 +#: ccdfunc.c:473 msgid "Can't set active wheel number" msgstr "" -#: ccdfunc.c:513 +#: ccdfunc.c:489 msgid "Can't get max wheel position" msgstr "" -#: ccdfunc.c:520 +#: ccdfunc.c:496 #, c-format msgid "Wheel position should be from 0 to %d" msgstr "" -#: ccdfunc.c:524 +#: ccdfunc.c:500 #, c-format msgid "Can't set wheel position %d" msgstr "" -#: ccdfunc.c:539 +#: ccdfunc.c:515 msgid "Camera plugin have no capture polling funtion." msgstr "" -#: ccdfunc.c:545 +#: ccdfunc.c:521 #, c-format msgid "%.1f seconds till exposition ends" msgstr "" -#: ccdfunc.c:560 +#: ccdfunc.c:536 msgid "Camera device not pointed" msgstr "" -#: ccdfunc.c:567 ccdfunc.c:568 +#: ccdfunc.c:543 ccdfunc.c:544 msgid "No cameras found" msgstr "" -#: ccdfunc.c:588 +#: ccdfunc.c:564 msgid "Camera plugin have no model name getter" msgstr "" -#: ccdfunc.c:599 +#: ccdfunc.c:575 #, c-format msgid "Found %d cameras, you point number %d" msgstr "" -#: ccdfunc.c:603 +#: ccdfunc.c:579 msgid "Can't set active camera number" msgstr "" -#: ccdfunc.c:609 +#: ccdfunc.c:585 msgid "Camera plugin have no custom commands" msgstr "" -#: ccdfunc.c:634 +#: ccdfunc.c:610 msgid "Camera plugin have no fun speed setter" msgstr "" -#: ccdfunc.c:637 +#: ccdfunc.c:613 msgid "Can't set fan speed" msgstr "" -#: ccdfunc.c:638 +#: ccdfunc.c:614 #, c-format msgid "Set fan speed to %d" msgstr "" -#: ccdfunc.c:644 +#: ccdfunc.c:619 #, c-format msgid "Camera model: %s" msgstr "" -#: ccdfunc.c:645 +#: ccdfunc.c:620 #, c-format msgid "Pixel size: %g x %g" msgstr "" -#: ccdfunc.c:651 +#: ccdfunc.c:626 #, c-format msgid "Full array: %s" msgstr "" -#: ccdfunc.c:654 +#: ccdfunc.c:629 #, c-format msgid "Field of view: %s" msgstr "" -#: ccdfunc.c:657 +#: ccdfunc.c:632 #, c-format msgid "Current format: %s" msgstr "" -#: ccdfunc.c:659 +#: ccdfunc.c:634 msgid "Camera plugin have no temperature setter" msgstr "" -#: ccdfunc.c:660 +#: ccdfunc.c:635 #, c-format msgid "Can't set T to %g degC" msgstr "" -#: ccdfunc.c:669 +#: ccdfunc.c:644 #, c-format msgid "Shutter command: %s\n" msgstr "" -#: ccdfunc.c:671 +#: ccdfunc.c:646 #, c-format msgid "Can't run shutter command %s (unsupported?)" msgstr "" -#: ccdfunc.c:674 +#: ccdfunc.c:649 #, c-format msgid "Try to configure I/O port as %d" msgstr "" -#: ccdfunc.c:676 +#: ccdfunc.c:651 msgid "Can't configure (unsupported?)" msgstr "" -#: ccdfunc.c:683 +#: ccdfunc.c:658 msgid "Can't get IOport state (unsupported?)" msgstr "" -#: ccdfunc.c:686 +#: ccdfunc.c:661 #, c-format msgid "Try to write %d to I/O port" msgstr "" -#: ccdfunc.c:688 +#: ccdfunc.c:663 msgid "Can't set IOport" msgstr "" -#: ccdfunc.c:695 +#: ccdfunc.c:670 #, c-format msgid "Set gain to %g" msgstr "" -#: ccdfunc.c:696 +#: ccdfunc.c:671 #, c-format msgid "Can't set gain to %g" msgstr "" -#: ccdfunc.c:701 +#: ccdfunc.c:676 #, c-format msgid "Set brightness to %g" msgstr "" -#: ccdfunc.c:702 +#: ccdfunc.c:677 #, c-format msgid "Can't set brightness to %g" msgstr "" -#: ccdfunc.c:708 server.c:280 +#: ccdfunc.c:683 server.c:280 #, c-format msgid "Can't set binning %dx%d" msgstr "" -#: ccdfunc.c:720 server.c:281 +#: ccdfunc.c:695 server.c:281 msgid "Can't set given geometry" msgstr "" -#: ccdfunc.c:724 +#: ccdfunc.c:699 #, c-format msgid "Can't set %d flushes" msgstr "" -#: ccdfunc.c:727 +#: ccdfunc.c:702 msgid "Camera plugin have no exposition setter" msgstr "" -#: ccdfunc.c:729 +#: ccdfunc.c:704 #, c-format msgid "Can't set exposure time to %f seconds" msgstr "" -#: ccdfunc.c:732 +#: ccdfunc.c:707 msgid "Can't change frame type" msgstr "" -#: ccdfunc.c:735 +#: ccdfunc.c:710 msgid "Can't set bit depth" msgstr "" -#: ccdfunc.c:737 +#: ccdfunc.c:712 msgid "Can't set readout speed" msgstr "" -#: ccdfunc.c:738 +#: ccdfunc.c:713 #, c-format msgid "Readout mode: %s" msgstr "" -#: ccdfunc.c:739 +#: ccdfunc.c:714 msgid "Only show statistics" msgstr "" -#: ccdfunc.c:742 +#: ccdfunc.c:717 msgid "Can't get current binning" msgstr "" -#: ccdfunc.c:766 +#: ccdfunc.c:741 #, c-format msgid "Capture frame %d" msgstr "" -#: ccdfunc.c:767 ccdfunc.c:842 server.c:149 server.c:150 +#: ccdfunc.c:742 ccdfunc.c:819 server.c:149 server.c:150 msgid "Camera plugin have no function `start exposition`" msgstr "" -#: ccdfunc.c:769 ccdfunc.c:844 server.c:155 server.c:156 +#: ccdfunc.c:744 ccdfunc.c:821 server.c:155 server.c:156 msgid "Can't start exposition" msgstr "" -#: ccdfunc.c:774 +#: ccdfunc.c:749 msgid "Can't capture image" msgstr "" -#: ccdfunc.c:777 +#: ccdfunc.c:752 msgid "Read grabbed image" msgstr "" -#: ccdfunc.c:779 ccdfunc.c:857 server.c:173 server.c:174 +#: ccdfunc.c:754 ccdfunc.c:834 server.c:173 server.c:174 msgid "Camera plugin have no function `capture`" msgstr "" -#: ccdfunc.c:781 ccdfunc.c:858 +#: ccdfunc.c:756 ccdfunc.c:835 msgid "Can't grab image" msgstr "" -#: ccdfunc.c:793 client.c:289 +#: ccdfunc.c:770 client.c:289 #, c-format msgid "%d seconds till pause ends\n" msgstr "" -#: ccdfunc.c:855 +#: ccdfunc.c:832 msgid "Some error when capture" msgstr "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index b1809dc..bd9b009 100644 --- a/locale/ru/ru.po +++ b/locale/ru/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2025-04-16 08:48+0300\n" + "POT-Creation-Date: 2026-02-11 17:12+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,12 +16,12 @@ msgstr "Project-Id-Version: PACKAGE VERSION\n" "Content-Type: text/plain; charset=koi8-r\n" "Content-Transfer-Encoding: 8bit\n" -#: ccdfunc.c:545 +#: ccdfunc.c:521 #, c-format msgid "%.1f seconds till exposition ends" msgstr "%.1f секунд до окончания экспозиции" -#: ccdfunc.c:793 client.c:289 +#: ccdfunc.c:770 client.c:289 #, c-format msgid "%d seconds till pause ends\n" msgstr "%d секунд до окончания паузы\n" @@ -38,95 +38,95 @@ msgstr " msgid "CMOS gain level" msgstr "уровень Gain CMOS" -#: ccdfunc.c:560 +#: ccdfunc.c:536 msgid "Camera device not pointed" msgstr "Устройство свеоприемника не подключено" -#: ccdfunc.c:197 +#: ccdfunc.c:198 msgid "Camera device unknown" msgstr "Устройство свеоприемника не опознано" -#: ccdfunc.c:644 +#: ccdfunc.c:619 #, c-format msgid "Camera model: %s" msgstr "Модель светоприемника: %s" -#: ccdfunc.c:539 +#: ccdfunc.c:515 #, fuzzy msgid "Camera plugin have no capture polling funtion." msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:609 +#: ccdfunc.c:585 msgid "Camera plugin have no custom commands" msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:727 +#: ccdfunc.c:702 #, fuzzy msgid "Camera plugin have no exposition setter" msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:634 +#: ccdfunc.c:610 #, fuzzy msgid "Camera plugin have no fun speed setter" msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:779 ccdfunc.c:857 server.c:173 server.c:174 +#: ccdfunc.c:754 ccdfunc.c:834 server.c:173 server.c:174 #, fuzzy msgid "Camera plugin have no function `capture`" msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:767 ccdfunc.c:842 server.c:149 server.c:150 +#: ccdfunc.c:742 ccdfunc.c:819 server.c:149 server.c:150 #, fuzzy msgid "Camera plugin have no function `start exposition`" msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:588 +#: ccdfunc.c:564 #, fuzzy msgid "Camera plugin have no model name getter" msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:659 +#: ccdfunc.c:634 #, fuzzy msgid "Camera plugin have no temperature setter" msgstr "У плагина камеры нет особых команд" -#: ccdfunc.c:774 +#: ccdfunc.c:749 msgid "Can't capture image" msgstr "Не могу захватить изображение" -#: ccdfunc.c:732 +#: ccdfunc.c:707 msgid "Can't change frame type" msgstr "Не могу изменить тип кадра" -#: ccdfunc.c:676 +#: ccdfunc.c:651 msgid "Can't configure (unsupported?)" msgstr "Не могу сконфигурировать (опция не поддерживается?)" -#: ccdfunc.c:683 +#: ccdfunc.c:658 msgid "Can't get IOport state (unsupported?)" msgstr "Не могу получить состояние порта I/O (не поддерживается?)" -#: ccdfunc.c:742 +#: ccdfunc.c:717 msgid "Can't get current binning" msgstr "Не могу получить текущее значение биннинга" -#: ccdfunc.c:427 +#: ccdfunc.c:404 msgid "Can't get current focuser position" msgstr "Не могу определить текущую позицию фокусера" -#: ccdfunc.c:420 +#: ccdfunc.c:397 msgid "Can't get focuser limit positions" msgstr "Не могу определить предельную позицию фокусера" -#: ccdfunc.c:513 +#: ccdfunc.c:489 msgid "Can't get max wheel position" msgstr "Не могу определить предельную позицию колеса" -#: ccdfunc.c:781 ccdfunc.c:858 +#: ccdfunc.c:756 ccdfunc.c:835 msgid "Can't grab image" msgstr "Не могу захватить изображение" -#: ccdfunc.c:445 +#: ccdfunc.c:422 msgid "Can't home focuser" msgstr "Не могу установить фокусер в нуль" @@ -142,103 +142,103 @@ msgstr " msgid "Can't open OpenGL window, image preview will be inaccessible" msgstr "Не могу открыть окно OpenGL, отображение будет недоступно" -#: ccdfunc.c:671 +#: ccdfunc.c:646 #, c-format msgid "Can't run shutter command %s (unsupported?)" msgstr "Не могу выполнить команду затвора %s (не поддерживается?)" -#: ccdfunc.c:220 +#: ccdfunc.c:221 #, c-format msgid "Can't save file with prefix %s" msgstr "Не могу сохранить файл с префиксом %s" -#: ccdfunc.c:724 +#: ccdfunc.c:699 #, c-format msgid "Can't set %d flushes" msgstr "Не могу установить %d сбросов" -#: ccdfunc.c:688 +#: ccdfunc.c:663 msgid "Can't set IOport" msgstr "Не могу поменять значения порта I/O" -#: ccdfunc.c:660 +#: ccdfunc.c:635 #, c-format msgid "Can't set T to %g degC" msgstr "Не могу установить температуру в %g градЦ" -#: ccdfunc.c:603 +#: ccdfunc.c:579 msgid "Can't set active camera number" msgstr "Не могу установить номер активной камеры" -#: ccdfunc.c:406 +#: ccdfunc.c:383 msgid "Can't set active focuser number" msgstr "Не могу установить номер активного фокусера" -#: ccdfunc.c:497 +#: ccdfunc.c:473 msgid "Can't set active wheel number" msgstr "Не могу установить номер активного колеса" -#: ccdfunc.c:708 server.c:280 +#: ccdfunc.c:683 server.c:280 #, c-format msgid "Can't set binning %dx%d" msgstr "Не могу установить биннинг %dx%d" -#: ccdfunc.c:735 +#: ccdfunc.c:710 msgid "Can't set bit depth" msgstr "Не могу установить разрядность АЦП" -#: ccdfunc.c:702 +#: ccdfunc.c:677 #, c-format msgid "Can't set brightness to %g" msgstr "Не могу установить яркость в %g" -#: ccdfunc.c:729 +#: ccdfunc.c:704 #, c-format msgid "Can't set exposure time to %f seconds" msgstr "Не могу установить экспозицию в %f секунд" -#: ccdfunc.c:637 +#: ccdfunc.c:613 msgid "Can't set fan speed" msgstr "Не могу установить скорость вентиляторов" -#: ccdfunc.c:696 +#: ccdfunc.c:671 #, c-format msgid "Can't set gain to %g" msgstr "Не могу установить Gain в %g" -#: ccdfunc.c:720 server.c:281 +#: ccdfunc.c:695 server.c:281 msgid "Can't set given geometry" msgstr "Не могу установить геометрию" -#: ccdfunc.c:447 +#: ccdfunc.c:424 #, c-format msgid "Can't set position %g" msgstr "Не могу изменить позицию на %g" -#: ccdfunc.c:441 +#: ccdfunc.c:418 #, c-format msgid "Can't set position %g: out of limits [%g, %g]" msgstr "Не могу установить позицию %g: вне пределов [%g, %g]" -#: ccdfunc.c:737 +#: ccdfunc.c:712 msgid "Can't set readout speed" msgstr "Не могу установить скорость считывания" -#: ccdfunc.c:524 +#: ccdfunc.c:500 #, c-format msgid "Can't set wheel position %d" msgstr "Не могу установить положение колеса %d" -#: ccdfunc.c:769 ccdfunc.c:844 server.c:155 server.c:156 +#: ccdfunc.c:744 ccdfunc.c:821 server.c:155 server.c:156 msgid "Can't start exposition" msgstr "Не могу начать экспозицию" -#: ccdfunc.c:766 +#: ccdfunc.c:741 #, c-format msgid "Capture frame %d" msgstr "Захват кадра %d" -#: ccdfunc.c:657 +#: ccdfunc.c:632 #, c-format msgid "Current format: %s" msgstr "Текущий формат: %s" @@ -252,40 +252,40 @@ msgstr " msgid "Equalization of histogram: %s" msgstr "Эквализация гистограммы: %s" -#: ccdfunc.c:277 +#: ccdfunc.c:278 msgid "Error saving file" msgstr "Ошибка сохранения файла" -#: ccdfunc.c:654 +#: ccdfunc.c:629 #, c-format msgid "Field of view: %s" msgstr "Поле зрения: %s" -#: ccdfunc.c:268 +#: ccdfunc.c:269 #, c-format msgid "File saved as '%s'" msgstr "Файл сохранен как '%s'" -#: ccdfunc.c:364 +#: ccdfunc.c:342 msgid "Focuser device not pointed" msgstr "Устройство фокусера не указано" -#: ccdfunc.c:599 +#: ccdfunc.c:575 #, c-format msgid "Found %d cameras, you point number %d" msgstr "Обнаружено %d камер, вы указали %d" -#: ccdfunc.c:402 +#: ccdfunc.c:379 #, c-format msgid "Found %d focusers, you point number %d" msgstr "Обнаружено %d фокусеров, вы указали %d" -#: ccdfunc.c:493 +#: ccdfunc.c:469 #, c-format msgid "Found %d wheels, you point number %d" msgstr "Обнаружено %d колес, вы указали %d" -#: ccdfunc.c:651 +#: ccdfunc.c:626 #, c-format msgid "Full array: %s" msgstr "Полный формат: %s" @@ -299,7 +299,7 @@ msgstr " msgid "INET image socket port" msgstr "порт локального сетевого сокета передачи изображения" -#: ccdfunc.c:355 +#: ccdfunc.c:333 #, c-format msgid "Image stat:\n" msgstr "Статистика по изображению: \n" @@ -312,32 +312,32 @@ msgstr "N msgid "No camera device" msgstr "Не указано устройство камеры" -#: ccdfunc.c:567 ccdfunc.c:568 +#: ccdfunc.c:543 ccdfunc.c:544 msgid "No cameras found" msgstr "Камер не обнаружено" -#: ccdfunc.c:371 +#: ccdfunc.c:349 msgid "No focusers found" msgstr "Фокусеров не обнаружено" -#: ccdfunc.c:462 +#: ccdfunc.c:439 msgid "No wheels found" msgstr "Турелей не обнаружено" -#: ccdfunc.c:739 +#: ccdfunc.c:714 msgid "Only show statistics" msgstr "Только отобразить статистику" -#: ccdfunc.c:645 +#: ccdfunc.c:620 #, c-format msgid "Pixel size: %g x %g" msgstr "Размер пикселя: %g x %g" -#: ccdfunc.c:777 +#: ccdfunc.c:752 msgid "Read grabbed image" msgstr "Считывание изображения" -#: ccdfunc.c:738 +#: ccdfunc.c:713 #, c-format msgid "Readout mode: %s" msgstr "Режим считывания: %s" @@ -346,36 +346,36 @@ msgstr " msgid "Server timeout" msgstr "Таймаут сервера" -#: ccdfunc.c:701 +#: ccdfunc.c:676 #, c-format msgid "Set brightness to %g" msgstr "Установить яркость в %g" -#: ccdfunc.c:638 +#: ccdfunc.c:614 #, c-format msgid "Set fan speed to %d" msgstr "Не могу установить скорость вентиляторов в %d" -#: ccdfunc.c:695 +#: ccdfunc.c:670 #, c-format msgid "Set gain to %g" msgstr "Установить Gain в %g" -#: ccdfunc.c:669 +#: ccdfunc.c:644 #, c-format msgid "Shutter command: %s\n" msgstr "Команда затвора: %s\n" -#: ccdfunc.c:855 +#: ccdfunc.c:832 msgid "Some error when capture" msgstr "Ошибка при захвате" -#: ccdfunc.c:674 +#: ccdfunc.c:649 #, c-format msgid "Try to configure I/O port as %d" msgstr "Попытка сконфигурировать порт I/O как %d" -#: ccdfunc.c:686 +#: ccdfunc.c:661 #, c-format msgid "Try to write %d to I/O port" msgstr "Попытка записи %d в порт I/O" @@ -384,11 +384,11 @@ msgstr " msgid "UNIX socket name (command socket)" msgstr "имя UNIX-сокета" -#: ccdfunc.c:455 +#: ccdfunc.c:432 msgid "Wheel device not pointed" msgstr "Устройство турели не указано" -#: ccdfunc.c:520 +#: ccdfunc.c:496 #, c-format msgid "Wheel position should be from 0 to %d" msgstr "Позиция колеса должна быть от 0 до %d"