From 869421d52f3807d09f018f986b08a4ee10632a1d Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Thu, 1 Feb 2024 16:19:41 +0300 Subject: [PATCH] add some FITS header functions, change FITSsave, add plugin commands --- CMakeLists.txt | 6 +- Dummy_cameras/CMakeLists.txt | 4 +- Dummy_cameras/dummyfunc.c | 38 +++- ccdcapture.c | 383 +++++++++++++++++++++++++++++------ ccdcapture.h | 84 +++++--- ccdfunc.c | 318 +++++++++++++---------------- ccdfunc.h | 1 + client.c | 23 ++- cmdlnopts.c | 38 ++-- cmdlnopts.h | 1 + examples/CMakeLists.txt | 2 +- examples/ccd_client.c | 134 ++++++++++++ locale/ru/messages.po | 300 ++++++++++++++------------- locale/ru/ru.po | 261 ++++++++++++------------ server.c | 49 +++-- 15 files changed, 1058 insertions(+), 584 deletions(-) create mode 100644 examples/ccd_client.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 046fea4..07513e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ option(APOGEE "Add support of Apogee cameras" OFF) option(EXAMPLES "Some examples" OFF) # default flags -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -fno-builtin-strlen") # change wrong behaviour with install prefix if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local") @@ -51,7 +51,7 @@ set(CMAKE_COLOR_MAKEFILE ON) # cmake -DDEBUG=yes -> debugging if(DEBUG) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Og -g3 -ggdb -fno-builtin-strlen -Werror") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Og -g3 -ggdb -Werror") add_definitions(-DEBUG) set(CMAKE_BUILD_TYPE DEBUG) set(CMAKE_VERBOSE_MAKEFILE "ON") @@ -122,7 +122,7 @@ set(RU_FILE ${LCPATH}/ru.po) add_library(${PROJLIB} SHARED ${LIBSRC}) add_executable(${PROJ} ${SOURCES} ${PO_FILE} ${MO_FILE}) target_link_libraries(${PROJ} ${CFITSIO_LIBRARIES} ${X11_LIBRARIES} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${${PROJ}_LIBRARIES} -lm ${CMAKE_DL_LIBS} ${PROJLIB}) -target_link_libraries(${PROJLIB} ${${PROJLIB}_LIBRARIES}) +target_link_libraries(${PROJLIB} ${CFITSIO_LIBRARIES} ${${PROJLIB}_LIBRARIES}) include_directories(${${PROJ}_INCLUDE_DIRS} .) link_directories(${${PROJ}_LIBRARY_DIRS} ) set(PCFILE "${CMAKE_BINARY_DIR}/${PROJLIB}.pc") diff --git a/Dummy_cameras/CMakeLists.txt b/Dummy_cameras/CMakeLists.txt index c98ba68..f0d9b0d 100644 --- a/Dummy_cameras/CMakeLists.txt +++ b/Dummy_cameras/CMakeLists.txt @@ -1,10 +1,12 @@ cmake_minimum_required(VERSION 3.20) set(CCDLIB devdummy) +SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + find_package(PkgConfig REQUIRED) pkg_check_modules(${CCDLIB} REQUIRED usefull_macros) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SRC) include_directories(${${CCDLIB}_INCLUDE_DIRS} ..) link_directories(${${CCDLIB}_LIBRARY_DIRS}) diff --git a/Dummy_cameras/dummyfunc.c b/Dummy_cameras/dummyfunc.c index 182ad27..fcb95b9 100644 --- a/Dummy_cameras/dummyfunc.c +++ b/Dummy_cameras/dummyfunc.c @@ -41,6 +41,8 @@ static float camtemp = -30., exptime = 0.; static cc_capture_status capstat = CAPTURE_NO; static double texpstart = 0.; static uint8_t bitpix = 16; // bit depth: 8 or 16 +// sinusoide periods +static double sinPx = 100., sinPy = 200.; static int campoll(cc_capture_status *st, float *remain){ if(capstat != CAPTURE_PROCESS){ @@ -79,7 +81,7 @@ static int camcapt(cc_IMG *ima){ uint16_t *d = &((uint16_t*)ima->data)[y*ima->w/curvbin]; for(int x = 0; x < x1; x += curhbin){ // sinusoide 100x200 //*d++ = (uint16_t)(((n+x)%100)/99.*65535.); - *d++ = (uint16_t)((1. + sin((n+x) * M_PI/50.)*sin((n+y) * M_PI/100.))*32767.); + *d++ = (uint16_t)((1. + sin((n+x) * (2.*M_PI)/sinPx)*sin((n+y) * (2.*M_PI)/sinPy))*32767.); } } }else{ @@ -88,7 +90,7 @@ static int camcapt(cc_IMG *ima){ uint8_t *d = &((uint8_t*)ima->data)[y*ima->w/curvbin]; for(int x = 0; x < x1; x += curhbin){ // sinusoide 100x200 //*d++ = (uint16_t)(((n+x)%100)/99.*65535.); - *d++ = (uint8_t)((1. + sin((n+x) * M_PI/50.)*sin((n+y) * M_PI/100.))*127.); + *d++ = (uint8_t)((1. + sin((n+x) * (2.*M_PI)/sinPx)*sin((n+y) * (2.*M_PI)/sinPy))*127.); } } } @@ -254,6 +256,37 @@ static int whlgetnam(char *n, int l){ return TRUE; } +static const char* const helpmsg = + "Dummy camera custom plugin commands:\n" + "\tpx - set/get sin period over X axis (pix)\n" + "\tpy - -//- over Y axis\n" +; +static const char* const pmust = "Period must be not less than 1"; +static const char *plugincmd(const char *str){ + static char ans[BUFSIZ+1]; + snprintf(ans, BUFSIZ, "%s", str); + char *val = cc_get_keyval(ans); + if(val){ // setters + if(0 == strcmp("px", ans)){ + double f = atof(val); + if(f < 1.) return pmust; + sinPx = f; + }else if(0 == strcmp("py", ans)){ + double f = atof(val); + if(f < 1.) return pmust; + sinPy = f; + } + } // getters/return + if(0 == strcmp("px", ans)){ + snprintf(ans, BUFSIZ, "px=%g", sinPx); + return (const char*) ans; + }else if(0 == strcmp("py", ans)){ + snprintf(ans, BUFSIZ, "yx=%g", sinPy); + return (const char*) ans; + } + return helpmsg; +} + static int stub(){ return TRUE; } @@ -275,6 +308,7 @@ __attribute__ ((visibility("default"))) cc_Camera camera = { .capture = camcapt, .cancel = camcancel, .startexposition = startexp, + .plugincmd = plugincmd, // setters: .setDevNo = setdevno, .setbrightness = camsetbrig, diff --git a/ccdcapture.c b/ccdcapture.c index c0501a2..90b9912 100644 --- a/ccdcapture.c +++ b/ccdcapture.c @@ -19,6 +19,7 @@ #include // isspace #include // dlopen/close #include +#include // for float max #include #include #include @@ -40,6 +41,7 @@ double __t0 = 0.; #endif static int ntries = 2; // amount of tries to send messages controlling the answer +double answer_timeout = 0.1; // timeout of waiting answer from server (not static for client.c) /** * @brief cc_open_socket - create socket and open it @@ -146,7 +148,6 @@ int cc_senddata(int fd, void *data, size_t l){ // simple wrapper over write: add missed newline and log data int cc_sendmessage(int fd, const char *msg, int l){ - FNAME(); if(fd < 1 || !msg || l < 1) return TRUE; // empty message static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // thread safe pthread_mutex_lock(&mutex); @@ -156,7 +157,7 @@ int cc_sendmessage(int fd, const char *msg, int l){ buflen = 1024 * (1 + l/1024); tmpbuf = realloc(tmpbuf, buflen); } - DBG("send to fd %d: %s [%d]", fd, msg, l); + DBG("send to fd %d:\n%s[%d]", fd, msg, l); memcpy(tmpbuf, msg, l); if(msg[l-1] != '\n') tmpbuf[l++] = '\n'; if(l != send(fd, tmpbuf, l, MSG_NOSIGNAL)){ @@ -175,7 +176,6 @@ int cc_sendmessage(int fd, const char *msg, int l){ return TRUE; } int cc_sendstrmessage(int fd, const char *msg){ - FNAME(); if(fd < 1 || !msg) return TRUE; // empty message int l = strlen(msg); return cc_sendmessage(fd, msg, l); @@ -194,10 +194,6 @@ static const char *resmessages[RESULT_NUM] = { }; const char *cc_hresult2str(cc_hresult r){ - /*red("ALL results:\n"); - for(cc_hresult res = 0; res < RESULT_NUM; ++res){ - printf("%d: %s\n", res, resmessages[res]); - }*/ if(r < 0 || r >= RESULT_NUM) return "BADRESULT"; return resmessages[r]; } @@ -216,7 +212,7 @@ cc_hresult cc_str2hresult(const char *str){ * @return `val` */ char *cc_get_keyval(char *keyval){ - //DBG("Got string %s", keyval); + DBG("Got string %s", keyval); // remove starting spaces in key while(isspace(*keyval)) ++keyval; char *val = strchr(keyval, '='); @@ -224,7 +220,7 @@ char *cc_get_keyval(char *keyval){ *val++ = 0; while(isspace(*val)) ++val; } - //DBG("val = %s (%zd bytes)", val, (val)?strlen(val):0); + DBG("val = %s (%zd bytes)", val, (val)?strlen(val):0); // remove trailing spaces in key char *e = keyval + strlen(keyval) - 1; // last key symbol while(isspace(*e) && e > keyval) --e; @@ -264,43 +260,6 @@ int cc_canberead(int fd){ return 0; } -/** - * @brief cc_setNtries, cc_getNtries - ntries setter and getter - * @param n - new amount of tries - * @return cc_setNtries returns TRUE if succeed, cc_getNtries returns current ntries value - */ -int cc_setNtries(int n){ - if(n > 1000 || n < 1) return FALSE; - ntries = n; - return TRUE; -} -int cc_getNtries(){return ntries;} - -static cc_hresult sendstrN(int fd, const char *str){ - for(int i = 0; i < ntries; ++i){ - if(!cc_sendstrmessage(fd, str)) continue; - double t0 = dtime(); - while(dtime() - t0 < CC_ANSWER_TIMEOUT){ - // TODO: continue the code - } - } - return FALSE; -} - -/** - * @brief cc_sendint - send integer value over socket (make 2 tries) - * @param fd - socket fd - * @param cmd - setter - * @param val - value - * @return answer received - */ -cc_hresult cc_sendint(int fd, const char *cmd, int val){ -#define BBUFS (63) - char buf[BBUFS+1]; - snprintf(buf, BBUFS, "%s=%d\n", cmd, val); - return sendstrN(fd, buf); -} - /** * @brief cc_getshm - get shared memory segment for image * @param imsize - size of image data (in bytes): if !=0 allocate as server, else - as client (readonly) @@ -411,26 +370,84 @@ int cc_getNbytes(cc_IMG *image){ return n; } -cc_charbuff *cc_bufnew(size_t size){ - DBG("Allocate new buffer with size %zd", size); - cc_charbuff *b = MALLOC(cc_charbuff, 1); - b->bufsize = size; - b->buf = MALLOC(char, size); +/** + * @brief cc_strbufnew - allocate new buffer + * @param bufsize - size of full socket buffer + * @param stringsize - max length of string from buffer (excluding \0) + * @return allocated buffer + */ +cc_strbuff *cc_strbufnew(size_t bufsize, size_t stringsize){ + if(bufsize < 8 || stringsize < 8){ + WARNX("Need to allocate at least 8 bytes in buffers"); + return NULL; + } + DBG("Allocate new string buffer with size %zd and string size %zd", bufsize, stringsize); + cc_strbuff *b = MALLOC(cc_strbuff, 1); + b->bufsize = bufsize; + b->buf = MALLOC(char, bufsize); + b->string = MALLOC(char, stringsize + 1); // for terminated zero + b->strlen = stringsize; return b; } +void cc_strbufdel(cc_strbuff **buf){ + FREE((*buf)->buf); + FREE((*buf)->string); + FREE(*buf); +} -void cc_bufdel(cc_charbuff **buf){ +cc_charbuff *cc_charbufnew(){ + DBG("Allocate new char buffer with size %d", BUFSIZ); + cc_charbuff *b = MALLOC(cc_charbuff, 1); + b->bufsize = BUFSIZ; + b->buf = MALLOC(char, BUFSIZ); + return b; +} +// set buflen to 0 +void cc_charbufclr(cc_charbuff *buf){ + if(!buf) return; + buf->buflen = 0; +} +// 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); + memcpy(b->buf + b->buflen, s, l); + b->buflen += l; + b->buf[b->buflen] = 0; +} +void cc_charbufaddline(cc_charbuff *b, const char *s){ + if(!b || !s) return; + size_t l = strlen(s); + if(l < 1 || !cc_charbuftest(b, l+2)) return; + cc_charbufput(b, s, l); + if(s[l-1] != '\n'){ // add trailing '\n' + b->buf[b->buflen++] = '\n'; + b->buf[b->buflen] = 0; + } +} +// realloc buffer if its free size less than maxsize +int cc_charbuftest(cc_charbuff *b, size_t maxsize){ + if(!b) return FALSE; + if(b->bufsize - b->buflen > maxsize + 1) return TRUE; + size_t newblks = (maxsize + BUFSIZ) / BUFSIZ; + b->bufsize += BUFSIZ * newblks; + DBG("Realloc charbuf to %zd", b->bufsize); + b->buf = realloc(b->buf, b->bufsize); + return TRUE; +} +void cc_charbufdel(cc_charbuff **buf){ FREE((*buf)->buf); FREE(*buf); } + /** * @brief cc_read2buf - try to read next data portion from POLLED socket * @param fd - socket fd to read from * @param buf - buffer to read * @return FALSE in case of buffer overflow or client disconnect, TRUE if got 0..n bytes of data */ -int cc_read2buf(int fd, cc_charbuff *buf){ +int cc_read2buf(int fd, cc_strbuff *buf){ int ret = FALSE; if(!buf) return FALSE; pthread_mutex_lock(&buf->mutex); @@ -446,30 +463,272 @@ ret: return ret; } +/** + * @brief cc_refreshbuf - same as cc_read2buf, but with polling + * @param fd - socket fd + * @param buf - buffer + * @return TRUE if got data + */ +int cc_refreshbuf(int fd, cc_strbuff *buf){ + if(!cc_canberead(fd)) return FALSE; + return cc_read2buf(fd, buf); +} + /** * @brief cc_getline - read '\n'-terminated string from `b` and substitute '\n' by 0 * @param b - input charbuf - * @param str (allocated outside) - string-receiver * @param len - length of `str` (including terminating zero) - * @return amount of bytes read + * @return amount of bytes read (idx > b->strlen in case of string buffer overflow) */ -size_t cc_getline(cc_charbuff *b, char *str, size_t len){ +size_t cc_getline(cc_strbuff *b){ if(!b) return 0; size_t idx = 0; pthread_mutex_lock(&b->mutex); - if(!b->buf) goto ret; - --len; // for terminating zero + if(!b->buf || !b->string) goto ret; char *ptr = b->buf; for(; idx < b->buflen; ++idx) if(*ptr++ == '\n') break; - if(idx == b->buflen) goto ret; - size_t minlen = (len > idx) ? idx : len; // prevent `str` overflow - memcpy(str, b->buf, minlen); - str[minlen] = 0; + if(idx == b->buflen){ + idx = 0; // didn't fount '\n' + goto ret; + } + size_t minlen = (b->strlen > idx) ? idx : b->strlen; // prevent `str` overflow + memcpy(b->string, b->buf, minlen); + b->string[minlen] = 0; if(++idx < b->buflen){ // move rest of data in buffer to beginning memmove(b->buf, b->buf+idx, b->buflen-idx); b->buflen -= idx; }else b->buflen = 0; + DBG("got string `%s`", b->string); ret: pthread_mutex_unlock(&b->mutex); return idx; } + + +/** + * @brief cc_setNtries, cc_getNtries - ntries setter and getter + * @param n - new amount of tries + * @return cc_setNtries returns TRUE if succeed, cc_getNtries returns current ntries value + */ +int cc_setNtries(int n){ + if(n > 1000 || n < 1) return FALSE; + ntries = n; + return TRUE; +} +int cc_getNtries(){return ntries;} + +/** + * @brief cc_setAnsTmout, cc_getAnsTmout - answer timeout setter/getter + * @param t - timeout, s (not less than 0.001s) + * @return true/timeout + */ +int cc_setAnsTmout(double t){ + if(t < 0.001) return FALSE; + answer_timeout = t; + return TRUE; +} +double cc_getAnsTmout(){return answer_timeout;} + + +/** + * @brief ask4cmd - send string `cmdwargs` like "par=val" + * @param fd - fd of socket + * @param buf - buffer to store data read from socket + * @param cmdwargs (i) - "par=val" + * @return RESULT_OK if got same string or other error + */ +static cc_hresult ask4cmd(int fd, cc_strbuff *buf, const char *cmdwargs){ + DBG("ask for command %s", cmdwargs); + char *key = strdup(cmdwargs); + cc_get_keyval(key); // pick out key from `cmdwargs` + int l = strlen(key); + cc_hresult ret = RESULT_FAIL; + for(int i = 0; i < ntries; ++i){ + DBG("Try %d time", i+1); + if(!cc_sendstrmessage(fd, cmdwargs)) continue; + double t0 = dtime(); + while(dtime() - t0 < answer_timeout){ + int r = cc_canberead(fd); + if(r == 0) continue; + else if(r < 0){ + LOGERR("Socket disconnected"); + WARNX("Socket disconnected"); + ret = RESULT_DISCONNECTED; + goto rtn; + } + while(cc_refreshbuf(fd, buf)); + DBG("read"); + size_t got = 0; + while((got = cc_getline(buf))){ + if(got >= BUFSIZ){ + DBG("Client fd=%d gave buffer overflow", fd); + LOGMSG("SERVER client fd=%d buffer overflow", fd); + }else if(got){ + if(strncmp(buf->string, key, l) == 0){ + ret = RESULT_OK; + goto rtn; + }else{ // answers like 'OK' etc + cc_hresult r = cc_str2hresult(buf->string); + if(r != RESULT_NUM){ // some other data + ret = r; + goto rtn; + } + } + } + cc_refreshbuf(fd, buf); + } + } + } +rtn: + DBG("returned with `%s`", cc_hresult2str(ret)); + FREE(key); + return ret; +} + +#define BBUFS (63) + +/** + * @brief cc_setint - send integer value over socket + * @param fd - socket fd + * @param cmd - setter + * @param val - new value + * @return answer received + */ +cc_hresult cc_setint(int fd, cc_strbuff *cbuf, const char *cmd, int val){ + char buf[BBUFS+1]; + snprintf(buf, BBUFS, "%s=%d\n", cmd, val); + return ask4cmd(fd, cbuf, buf); +} +/** + * @brief cc_getint - getter for integer value + */ +cc_hresult cc_getint(int fd, cc_strbuff *cbuf, const char *cmd, int *val){ + char buf[BBUFS+1]; + snprintf(buf, BBUFS, "%s\n", cmd); + cc_hresult r = ask4cmd(fd, cbuf, buf); + if(r == RESULT_OK){ + char *sv = cc_get_keyval(cbuf->string); + if(!sv) return RESULT_FAIL; + char *ep; + long L = strtol(sv, &ep, 0); + if(sv == ep || L < INT_MIN || L > INT_MAX) return RESULT_BADVAL; + if(val) *val = (int) L; + } + return r; +} + +/** + * @brief cc_setfloat - send float value over socket + * @param fd - socket fd + * @param cmd - setter + * @param val - new value + * @return answer received + */ +cc_hresult cc_setfloat(int fd, cc_strbuff *cbuf, const char *cmd, float val){ + char buf[BBUFS+1]; + snprintf(buf, BBUFS, "%s=%g\n", cmd, val); + return ask4cmd(fd, cbuf, buf); +} +/** + * @brief cc_getfloat - getter for float value + */ +cc_hresult cc_getfloat(int fd, cc_strbuff *cbuf, const char *cmd, float *val){ + char buf[BBUFS+1]; + snprintf(buf, BBUFS, "%s\n", cmd); + cc_hresult r = ask4cmd(fd, cbuf, buf); + if(r == RESULT_OK){ + char *sv = cc_get_keyval(cbuf->string); + if(!sv) return RESULT_FAIL; + char *ep; + double d = strtod(sv, &ep); + if(sv == ep || d < (-FLT_MAX) || d > FLT_MAX) return RESULT_BADVAL; + if(val) *val = (float)d; + } + return r; +} + + +// get next record from external buffer, newlines==1 if every record ends with '\n' +char *cc_nextkw(char *buf, char record[FLEN_CARD+1], int newlines){ + char *nextline = NULL; + int l = FLEN_CARD - 1; + if(newlines){ + char *e = strchr(buf, '\n'); + if(e){ + if(e - buf < FLEN_CARD) l = e - buf; + nextline = e + 1; + } + }else nextline = buf + (FLEN_CARD - 1); + strncpy(record, buf, l); + record[l] = 0; + return nextline; +} + +/** + * @brief cc_kwfromfile - add records from file + * @param b - buffer to add + * @param filename - file name with FITS headers ('\n'-terminated or by 80 chars) + * @return amount of bytes added + */ +size_t cc_kwfromfile(cc_charbuff *b, char *filename){ + if(!b) return 0; + mmapbuf *buf = My_mmap(filename); + if(!buf || buf->len < 1){ + WARNX("Can't add FITS records from file %s", filename); + LOGWARN("Can't add FITS records from file %s", filename); + return 0; + } + size_t blen0 = b->buflen; + char rec[FLEN_CARD+1], card[FLEN_CARD+1]; + char *data = buf->data, *x = strchr(data, '\n'), *eodata = buf->data + buf->len; + int newlines = 0; + if(x && (x - data) < FLEN_CARD){ // we found newline -> this is a format with newlines + newlines = 1; + } + do{ + data = cc_nextkw(data, rec, newlines); + if(data > eodata) break; + int status = 0, kt = 0; + fits_parse_template(rec, card, &kt, &status); + if(status) fits_report_error(stderr, status); + else cc_charbufaddline(b, card); + }while(data && *data); + My_munmap(buf); + return b->buflen - blen0; +} + +/** + * @brief cc_charbuf2kw - write all keywords from `b` to file `f` + * `b` should be prepared by cc_kwfromfile or similar + * @param b - buffer with '\n'-separated FITS keys + * @param f - file to write + * @return FALSE if failed + */ +int cc_charbuf2kw(cc_charbuff *b, fitsfile *f){ + if(!b || !f || !b->buflen) return FALSE; + char key[FLEN_KEYWORD + 1], card[FLEN_CARD+1]; // keyword to update + char *c = b->buf, *eof = b->buf + b->buflen; + while(c < eof){ + char *e = strchr(c, '\n'); + if(!e || e > eof) break; + //char *ek = strchr(c, ' '); + char *eq = strchr(c, '='); + //if(eq > ek) eq = ek; // if keyword is shorter than 8 letters + //size_t l = eq-c; if(l > FLEN_KEYWORD) l = FLEN_KEYWORD; + //memcpy(key, c, l); key[l] = 0; + memcpy(key, c, 8); key[8] = 0; + size_t l = e - c; if(l > FLEN_CARD) l = FLEN_CARD; + memcpy(card, c, l); card[l] = 0; + int status = 0; + if(eq - c == 8){ // key = val + DBG("Update key `%s` with `%s`", key, card); + fits_update_card(f, key, card, &status); + }else{ // comment etc + DBG("Write full record `%s`", card); + fits_write_record(f, card, &status); + } + if(status) fits_report_error(stderr, status); + c = e + 1; + } + return TRUE; +} diff --git a/ccdcapture.h b/ccdcapture.h index c6af47c..cf8a0b9 100644 --- a/ccdcapture.h +++ b/ccdcapture.h @@ -17,6 +17,8 @@ */ #pragma once + +#include // FLEN_CARD #include #include #include // for size_t @@ -30,6 +32,7 @@ typedef struct __attribute__((packed, aligned(4))){ double timestamp; // timestamp of image taken uint8_t bitpix; // bits per pixel (8 or 16) int w, h; // image size + int gotstat; // stat counted uint16_t max, min; // min/max values float avr, std; // statistics size_t bytelen; // size of image in bytes @@ -107,6 +110,7 @@ typedef struct{ int (*getTbody)(float *t); // body T int (*getbin)(int *binh, int *binv); int (*getio)(int *s); // get IO-port state + const char* (*plugincmd)(const char *str); // 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 cc_frameformat array; // array format @@ -145,11 +149,6 @@ typedef struct{ int (*getMaxPos)(int *p); // amount of positions } cc_Wheel; -cc_Focuser *open_focuser(const char *pluginname); -cc_Camera *open_camera(const char *pluginname); -cc_Wheel *open_wheel(const char *pluginname); -int cc_getNbytes(cc_IMG *image); - /****** Content of old socket.h ******/ // max & min TCP socket port number @@ -161,8 +160,6 @@ int cc_getNbytes(cc_IMG *image); // wait for mutex locking #define CC_BUSY_TIMEOUT (1.0) -// waiting for answer timeout -#define CC_ANSWER_TIMEOUT (0.01) // wait for exposition ends (between subsequent check calls) #define CC_WAIT_TIMEOUT (2.0) // client will disconnect after this time from last server message @@ -179,11 +176,6 @@ typedef enum{ RESULT_NUM } cc_hresult; -const char *cc_hresult2str(cc_hresult r); -cc_hresult cc_str2hresult(const char *str); -int cc_setNtries(int n); -int cc_getNtries(); - // fd - socket fd to send private messages, key, val - key and its value typedef cc_hresult (*cc_mesghandler)(int fd, const char *key, const char *val); @@ -193,16 +185,6 @@ typedef struct{ const char *key; // keyword } cc_handleritem; -int cc_open_socket(int isserver, char *path, int isnet); -int cc_senddata(int fd, void *data, size_t l); -int cc_sendmessage(int fd, const char *msg, int l); -int cc_sendstrmessage(int fd, const char *msg); -char *cc_get_keyval(char *keyval); -cc_IMG *cc_getshm(key_t key, size_t imsize); -int cc_canberead(int fd); -cc_hresult cc_sendint(int fd, const char *cmd, int val); - - /****** Content of old server.h ******/ typedef enum{ @@ -224,6 +206,7 @@ typedef enum{ #define CC_CMD_SHMEMKEY "shmemkey" // CCD/CMOS +#define CC_CMD_PLUGINCMD "plugincmd" #define CC_CMD_CAMLIST "camlist" #define CC_CMD_CAMDEVNO "camdevno" #define CC_CMD_EXPOSITION "exptime" @@ -252,6 +235,7 @@ typedef enum{ #define CC_CMD_DARK "dark" #define CC_CMD_INFTY "infty" // FITS file keywords +#define CC_CMD_GETHEADERS "getheaders" #define CC_CMD_AUTHOR "author" #define CC_CMD_INSTRUMENT "instrument" #define CC_CMD_OBSERVER "observer" @@ -270,6 +254,15 @@ typedef enum{ #define CC_CMD_WDEVNO "wdevno" #define CC_CMD_WPOS "wpos" +typedef struct{ + char* buf; // databuffer + size_t bufsize; // size of `buf` + size_t buflen; // current buffer length + char *string; // last \n-ended string from `buf` + size_t strlen; // max length of `string` + pthread_mutex_t mutex; // mutex for atomic data access +} cc_strbuff; + typedef struct{ char* buf; // databuffer size_t bufsize; // size of `buf` @@ -277,7 +270,46 @@ typedef struct{ pthread_mutex_t mutex; // mutex for atomic data access } cc_charbuff; -cc_charbuff *cc_bufnew(size_t size); -void cc_bufdel(cc_charbuff **buf); -int cc_read2buf(int fd, cc_charbuff *buf); -size_t cc_getline(cc_charbuff *b, char *str, size_t len); +#define cc_buff_lock(b) pthread_mutex_lock(&b->mutex) +#define cc_buff_trylock(b) pthread_mutex_trylock(&b->mutex) +#define cc_buff_unlock(b) pthread_mutex_unlock(&b->mutex) + +cc_Focuser *open_focuser(const char *pluginname); +cc_Camera *open_camera(const char *pluginname); +cc_Wheel *open_wheel(const char *pluginname); + +cc_charbuff *cc_charbufnew(); +int cc_charbuftest(cc_charbuff *b, size_t maxsize); +void cc_charbufclr(cc_charbuff *buf); +void cc_charbufdel(cc_charbuff **buf); +void cc_charbufput(cc_charbuff *b, const char *s, size_t l); +void cc_charbufaddline(cc_charbuff *b, const char *s); +cc_strbuff *cc_strbufnew(size_t size, size_t stringsize); +void cc_strbufdel(cc_strbuff **buf); + +const char *cc_hresult2str(cc_hresult r); +cc_hresult cc_str2hresult(const char *str); +int cc_setNtries(int n); +int cc_getNtries(); +int cc_setAnsTmout(double t); +double cc_getAnsTmout(); +int cc_getNbytes(cc_IMG *image); + +int cc_read2buf(int fd, cc_strbuff *buf); +int cc_refreshbuf(int fd, cc_strbuff *buf); +size_t cc_getline(cc_strbuff *b); +int cc_open_socket(int isserver, char *path, int isnet); +int cc_senddata(int fd, void *data, size_t l); +int cc_sendmessage(int fd, const char *msg, int l); +int cc_sendstrmessage(int fd, const char *msg); +char *cc_get_keyval(char *keyval); +cc_IMG *cc_getshm(key_t key, size_t imsize); +int cc_canberead(int fd); +cc_hresult cc_setint(int fd, cc_strbuff *cbuf, const char *cmd, int val); +cc_hresult cc_getint(int fd, cc_strbuff *cbuf, const char *cmd, int *val); +cc_hresult cc_setfloat(int fd, cc_strbuff *cbuf, const char *cmd, float val); +cc_hresult cc_getfloat(int fd, cc_strbuff *cbuf, const char *cmd, float *val); + +char *cc_nextkw(char *buf, char record[FLEN_CARD+1], int newlines); +size_t cc_kwfromfile(cc_charbuff *b, char *filename); +int cc_charbuf2kw(cc_charbuff *b, fitsfile *f); diff --git a/ccdfunc.c b/ccdfunc.c index c7ddd28..28d69b9 100644 --- a/ccdfunc.c +++ b/ccdfunc.c @@ -73,59 +73,118 @@ static int check_filenameprefix(char *buff, int buflen){ return FALSE; } -// get next record from external text file, newlines==1 if every record ends with '\n' -static char *getnextrec(char *buf, char *record, int newlines){ - char *nextline = NULL; - int l = FLEN_CARD - 1; - if(newlines){ - char *e = strchr(buf, '\n'); - if(e){ - if(e - buf < FLEN_CARD) l = e - buf; - nextline = e + 1; - } - }else nextline = buf + (FLEN_CARD - 1); - strncpy(record, buf, l); - record[l] = 0; - return nextline; -} +cc_charbuff *getFITSheader(cc_IMG *img){ + static cc_charbuff charbuf = {0}; + cc_charbufclr(&charbuf); + char card[FLEN_CARD+1], templ[2*FLEN_CARD+1], bufc[FLEN_CARD+1]; +#define FORMKW(in) \ +do{ int status = 0, kt = 0; \ + fits_parse_template(in, card, &kt, &status); \ + if(status) fits_report_error(stderr, status);\ + else{cc_charbufaddline(&charbuf, card);} \ +}while(0) +#define FORMINT(key, val, comment) do{ \ + snprintf(templ, FLEN_CARD, "%s = %d / %s", key, val, comment); \ + FORMKW(templ); \ +}while(0) +#define FORMFLT(key, val, comment) do{ \ + snprintf(templ, FLEN_CARD, "%s = %g / %s", key, val, comment); \ + FORMKW(templ); \ +}while(0) +#define FORMSTR(key, val, comment) do{ \ + snprintf(templ, 2*FLEN_CARD, "%s = '%s' / %s", key, val, comment); \ + FORMKW(templ); \ +}while(0) + calculate_stat(img); + float tmpf = 0.0; + int tmpi = 0; + /* FORMKW("COMMENT this is just a test comment - 0"); + FORMKW("COMMENT this is just a test comment - 1"); + FORMKW("COMMENT this is just a test comment - 2"); + FORMKW("HIERARCH longsome1 = 'this is just a test comment'"); + FORMKW("HIERARCH longsome2 = 'this is just a test comment'"); + FORMKW("HIERARCH longsome3 = 'this is just a test comment'");*/ + FORMKW("ORIGIN = 'SAO RAS' / Organization responsible for the data"); + FORMKW("OBSERVAT = 'Special Astrophysical Observatory, Russia' / Observatory name"); + FORMKW("INSTRUME = 'direct imaging' / Instrument"); + snprintf(templ, FLEN_CARD, "VIEWFLD = '(%d, %d)(%d, %d)' / Camera maximal field of view", camera->field.xoff, camera->field.yoff, + camera->field.xoff + camera->field.w, camera->field.yoff + camera->field.h); + FORMKW(templ); + snprintf(templ, FLEN_CARD, "ARRAYFLD = '(%d, %d)(%d, %d)' / Camera full array size (with overscans)", camera->array.xoff, camera->array.yoff, + camera->array.xoff + camera->array.w, camera->array.yoff + camera->array.h); + FORMKW(templ); + snprintf(templ, FLEN_CARD, "GEOMETRY = '(%d, %d)(%d, %d)' / Camera current frame geometry", camera->geometry.xoff, camera->geometry.yoff, + camera->geometry.xoff + camera->geometry.w, camera->geometry.yoff + camera->geometry.h); + FORMKW(templ); + if(GP->X0 > -1) FORMINT("X0", GP->X0, "Subframe left border without binning"); + if(GP->Y0 > -1) FORMINT("Y0", GP->Y0, "Subframe upper border without binning"); + if(GP->dark) sprintf(bufc, "dark"); + else if(GP->objtype) strncpy(bufc, GP->objtype, FLEN_CARD); + else sprintf(bufc, "light"); + FORMSTR("IMAGETYP", bufc, "Image type"); + FORMINT("DATAMIN", 0, "Min pixel value"); + FORMINT("DATAMAX", (1<bitpix) - 1, "Max pixel value"); + FORMINT("STATMIN", img->min, "Min data value"); + FORMINT("STATMAX", img->max, "Max data value"); + FORMFLT("STATAVR", img->avr, "Average data value"); + FORMFLT("STATSTD", img->std, "Std. of data value"); + if(camera->getTcold && camera->getTcold(&tmpf)) + FORMFLT("CAMTEMP", tmpf, "Camera temperature at exp. end, degr C"); + if(camera->getTbody && camera->getTbody(&tmpf)) + FORMFLT("BODYTEMP", tmpf, "Camera body temperature at exp. end, degr C"); + if(camera->getThot && camera->getThot(&tmpf)) + FORMFLT("HOTTEMP", tmpf, "Camera peltier hot side temperature at exp. end, degr C"); + FORMFLT( "EXPTIME", GP->exptime, "Actual exposition time (sec)"); + if(camera->getgain && camera->getgain(&tmpf)) + FORMFLT("CAMGAIN", tmpf, "CMOS gain value"); + if(camera->getbrightness && camera->getbrightness(&tmpf)) + FORMFLT("CAMBRIGH", tmpf, "CMOS brightness value"); -/** - * @brief addrec - add FITS records from file - * @param f (i) - FITS filename - * @param filename (i) - name of file - */ -static void addrec(fitsfile *f, char *filename){ - mmapbuf *buf = My_mmap(filename); - char rec[FLEN_CARD]; - if(!buf || buf->len < 1){ - WARNX("Empty header file %s", filename); - return; + snprintf(templ, 2*FLEN_CARD, "TIMESTAM = %.3f / Time of acquisition end (UNIX)", img->timestamp); + FORMKW(templ); + // BINNING / Binning + snprintf(templ, FLEN_CARD, "BINNING = '%d x %d' / Binning (hbin x vbin)", GP->hbin, GP->vbin); + FORMKW(templ); + FORMINT("XBINNING", GP->hbin, "Binning factor used on X axis"); + FORMINT("YBINNING", GP->vbin, "Binning factor used on Y axis"); + if(focuser){ // there is a focuser device - add info + if(focuser->getModelName && focuser->getModelName(bufc, FLEN_CARD)) + FORMSTR("FOCUSER", bufc, "Focuser model"); + if(focuser->getPos && focuser->getPos(&tmpf)) + FORMFLT("FOCUS", tmpf, "Current focuser position, mm"); + if(focuser->getMinPos && focuser->getMinPos(&tmpf)) + FORMFLT("FOCMIN", tmpf, "Minimal focuser position, mm"); + if(focuser->getMaxPos && focuser->getMaxPos(&tmpf)) + FORMFLT("FOCMAX", tmpf, "Maximal focuser position, mm"); + if(focuser->getTbody && focuser->getTbody(&tmpf)) + FORMFLT("FOCTEMP", tmpf, "Focuser body temperature, degr C"); } - char *data = buf->data, *x = strchr(data, '\n'), *eodata = buf->data + buf->len; - int newlines = 0; - if(x && (x - data) < FLEN_CARD){ // we found newline -> this is a format with newlines - newlines = 1; - } - do{ - data = getnextrec(data, rec, newlines); - verbose(4, "check record _%s_", rec); - int keytype, status = 0; - char newcard[FLEN_CARD], keyname[FLEN_CARD]; - fits_parse_template(rec, newcard, &keytype, &status); - if(status){ - fits_report_error(stderr, status); - continue; + if(wheel){ // there is a filter wheel device - add info + if(wheel->getModelName && wheel->getModelName(bufc, FLEN_CARD)){ + FORMSTR("WHEEL", bufc, "Filter wheel model"); } - verbose(4, "reformatted to _%s_", newcard); - strncpy(keyname, newcard, FLEN_CARD); - char *eq = strchr(keyname, '='); if(eq) *eq = 0; - eq = strchr(keyname, ' '); if(eq) *eq = 0; - //DBG("keyname: %s", keyname); - fits_update_card(f, keyname, newcard, &status); - if(status) fits_report_error(stderr, status); - if(data > eodata) break; - }while(data && *data); - My_munmap(buf); + if(wheel->getPos && wheel->getPos(&tmpi)) + FORMINT("FILTER", tmpi, "Current filter number"); + if(wheel->getMaxPos && wheel->getMaxPos(&tmpi)) + FORMINT("FILTMAX", tmpi, "Amount of filter positions"); + if(wheel->getTbody && wheel->getTbody(&tmpf)) + FORMFLT("FILTTEMP", tmpf, "Filter wheel body temperature, degr C"); + } + if(GP->addhdr){ // add records from files + char **nxtfile = GP->addhdr; + while(*nxtfile){ + cc_kwfromfile(&charbuf, *(nxtfile++)); + } + } + // add these keywords after all to override records from files + if(GP->observers) FORMSTR("OBSERVER", GP->observers, "Observers"); + if(GP->prog_id) FORMSTR("PROG-ID", GP->prog_id, "Observation program identifier"); + if(GP->author) FORMSTR("AUTHOR", GP->author, "Author of the program"); + if(GP->objname) FORMSTR("OBJECT", GP->objname, "Object name"); + if(camera->getModelName && camera->getModelName(bufc, FLEN_CARD)) + FORMSTR("DETECTOR", bufc, "Detector model"); + if(GP->instrument) FORMSTR("INSTRUME", GP->instrument, "Instrument"); + return &charbuf; } // save FITS file `img` into GP->outfile or GP->outfileprefix_XXXX.fits @@ -138,7 +197,7 @@ int saveFITS(cc_IMG *img, char **outp){ WARNX(_("Camera device unknown")); return FALSE; } - char buff[PATH_MAX+1], fnam[PATH_MAX+1]; + char fnam[PATH_MAX+1]; if(!GP->outfile && !GP->outfileprefix){ LOGWARN("Image not saved: neither filename nor filename prefix pointed"); return FALSE; @@ -163,13 +222,8 @@ int saveFITS(cc_IMG *img, char **outp){ LOGERR("Can't save image with prefix %s", GP->outfileprefix); } } - calculate_stat(img); - int width = img->w, height = img->h; long naxes[2] = {width, height}; - double tmpd = 0.0; - float tmpf = 0.0; - int tmpi = 0; struct tm *tm_time; char bufc[FLEN_CARD]; double dsavetime = dtime(); @@ -182,129 +236,29 @@ int saveFITS(cc_IMG *img, char **outp){ if(nbytes == 1) TRYFITS(fits_create_img, fp, BYTE_IMG, 2, naxes); else TRYFITS(fits_create_img, fp, USHORT_IMG, 2, naxes); if(fitserror) goto cloerr; - // ORIGIN / organization responsible for the data - WRITEKEY(fp, TSTRING, "ORIGIN", "SAO RAS", "organization responsible for the data"); - // OBSERVAT / Observatory name - WRITEKEY(fp, TSTRING, "OBSERVAT", "Special Astrophysical Observatory, Russia", "Observatory name"); - WRITEKEY(fp, TSTRING, "INSTRUME", "direct imaging", "Instrument"); - snprintf(bufc, FLEN_VALUE, "(%d, %d)(%d, %d)", camera->field.xoff, camera->field.yoff, - camera->field.xoff + camera->field.w, camera->field.yoff + camera->field.h); - WRITEKEY(fp, TSTRING, "VIEWFLD", bufc, "Camera maximal field of view"); - snprintf(bufc, FLEN_VALUE, "(%d, %d)(%d, %d)", camera->array.xoff, camera->array.yoff, - camera->array.xoff + camera->array.w, camera->array.yoff + camera->array.h); - WRITEKEY(fp, TSTRING, "ARRAYFLD", bufc, "Camera full array size (with overscans)"); - snprintf(bufc, FLEN_VALUE, "(%d, %d)(%d, %d)", camera->geometry.xoff, camera->geometry.yoff, - camera->geometry.xoff + camera->geometry.w, camera->geometry.yoff + camera->geometry.h); - WRITEKEY(fp, TSTRING, "GEOMETRY", bufc, "Camera current frame geometry"); // CRVAL1, CRVAL2 / Offset in X, Y - if(GP->X0 > -1) WRITEKEY(fp, TINT, "X0", &GP->X0, "Subframe left border without binning"); - if(GP->Y0 > -1) WRITEKEY(fp, TINT, "Y0", &GP->Y0, "Subframe upper border without binning"); - if(GP->dark) sprintf(bufc, "dark"); - else if(GP->objtype) strncpy(bufc, GP->objtype, FLEN_CARD-1); - else sprintf(bufc, "light"); - // IMAGETYP / object, flat, dark, bias, scan, eta, neon, push - WRITEKEY(fp, TSTRING, "IMAGETYP", bufc, "Image type"); - // DATAMAX, DATAMIN / Max, min pixel value - tmpi = 0; - WRITEKEY(fp, TINT, "DATAMIN", &tmpi, "Min pixel value"); - tmpi = (1<bitpix) - 1; - WRITEKEY(fp, TINT, "DATAMAX", &tmpi, "Max pixel value"); - tmpi = img->min; - WRITEKEY(fp, TUSHORT, "STATMIN", &tmpi, "Min data value"); - tmpi = img->max; - WRITEKEY(fp, TUSHORT, "STATMAX", &tmpi, "Max data value"); - tmpf = img->avr; - WRITEKEY(fp, TFLOAT, "STATAVR", &tmpf, "Average data value"); - tmpf = img->std; - WRITEKEY(fp, TFLOAT, "STATSTD", &tmpf, "Std. of data value"); -// WRITEKEY(fp, TFLOAT, "CAMTEMP0", &GP->temperature, "Camera temperature at exp. start, degr C"); - if(camera->getTcold(&tmpf)) - WRITEKEY(fp, TFLOAT, "CAMTEMP", &tmpf, "Camera temperature at exp. end, degr C"); - if(camera->getTbody(&tmpf)) - WRITEKEY(fp, TFLOAT, "BODYTEMP", &tmpf, "Camera body temperature at exp. end, degr C"); - if(camera->getThot(&tmpf)) - WRITEKEY(fp, TFLOAT, "HOTTEMP", &tmpf, "Camera peltier hot side temperature at exp. end, degr C"); - // EXPTIME / actual exposition time (sec) - tmpd = GP->exptime; - WRITEKEY(fp, TDOUBLE, "EXPTIME", &tmpd, "Actual exposition time (sec)"); - if(camera->getgain(&tmpf)){ - WRITEKEY(fp, TFLOAT, "CAMGAIN", &tmpf, "CMOS gain value"); - } - if(camera->getbrightness(&tmpf)){ - WRITEKEY(fp, TFLOAT, "CAMBRIGH", &tmpf, "CMOS brightness value"); - } - // DATE / Creation date (YYYY-MM-DDThh:mm:ss, UTC) - strftime(bufc, FLEN_VALUE, "%Y-%m-%dT%H:%M:%S", gmtime(&savetime)); - WRITEKEY(fp, TSTRING, "DATE", bufc, "Creation date (YYYY-MM-DDThh:mm:ss, UTC)"); + cc_charbuff *bufhdr = getFITSheader(img); + cc_charbuf2kw(bufhdr, fp); + // creation date/time + int s = 0; + fits_write_date(fp, &s); +/* +s = 0; +fits_write_comment(fp, bufhdr->buf, &s); +s = 0; +fits_write_history(fp, bufhdr->buf, &s); +*/ tm_time = localtime(&savetime); - strftime(bufc, FLEN_VALUE, "File creation time (UNIX)", tm_time); - WRITEKEY(fp, TDOUBLE, "UNIXTIME", &dsavetime, bufc); - WRITEKEY(fp, TDOUBLE, "TIMESTAM", &img->timestamp, "Time of acquisition end"); - strftime(bufc, 80, "%Y/%m/%d", tm_time); - // DATE-OBS / DATE (YYYY/MM/DD) OF OBS. - WRITEKEY(fp, TSTRING, "DATE-OBS", bufc, "DATE OF OBS. (YYYY/MM/DD, local)"); - strftime(bufc, 80, "%H:%M:%S", tm_time); + WRITEKEY(fp, TDOUBLE, "UNIXTIME", &dsavetime, "File creation time (UNIX)"); + strftime(bufc, FLEN_VALUE, "%Y/%m/%d", tm_time); + WRITEKEY(fp, TSTRING, "DATE-OBS", bufc, "Date of observation (YYYY/MM/DD, local)"); + strftime(bufc, FLEN_VALUE, "%H:%M:%S", tm_time); WRITEKEY(fp, TSTRING, "TIME", bufc, "Creation time (hh:mm:ss, local)"); - // BINNING / Binning - if(GP->hbin != 1 || GP->vbin != 1){ - snprintf(bufc, 80, "%d x %d", GP->hbin, GP->vbin); - WRITEKEY(fp, TSTRING, "BINNING", bufc, "Binning (hbin x vbin)"); - tmpi = GP->hbin; - WRITEKEY(fp, TINT, "XBINNING", &tmpi, "binning factor used on X axis"); - tmpi = GP->vbin; - WRITEKEY(fp, TINT, "YBINNING", &tmpi, "binning factor used on Y axis"); - } - if(focuser){ // there is a focuser device - add info - if(focuser->getModelName(buff, PATH_MAX)) - WRITEKEY(fp, TSTRING, "FOCUSER", buff, "Focuser model"); - if(focuser->getPos(&tmpf)) - WRITEKEY(fp, TFLOAT, "FOCUS", &tmpf, "Current focuser position, mm"); - if(focuser->getMinPos(&tmpf)) - WRITEKEY(fp, TFLOAT, "FOCMIN", &tmpf, "Minimal focuser position, mm"); - if(focuser->getMaxPos(&tmpf)) - WRITEKEY(fp, TFLOAT, "FOCMAX", &tmpf, "Maximal focuser position, mm"); - if(focuser->getTbody(&tmpf)) - WRITEKEY(fp, TFLOAT, "FOCTEMP", &tmpf, "Focuser body temperature, degr C"); - } - if(wheel){ // there is a filter wheel device - add info - if(wheel->getModelName(buff, PATH_MAX)) - WRITEKEY(fp, TSTRING, "WHEEL", buff, "Filter wheel model"); - if(wheel->getPos(&tmpi)) - WRITEKEY(fp, TINT, "FILTER", &tmpi, "Current filter number"); - if(wheel->getMaxPos(&tmpi)) - WRITEKEY(fp, TINT, "FILTMAX", &tmpi, "Amount of filter positions"); - if(wheel->getTbody(&tmpf)) - WRITEKEY(fp, TFLOAT, "FILTTEMP", &tmpf, "Filter wheel body temperature, degr C"); - } - if(GP->addhdr){ // add records from files - char **nxtfile = GP->addhdr; - while(*nxtfile){ - addrec(fp, *nxtfile++); - } - } - // add these keywords after all to change things in files with static records - // OBSERVER / Observers - if(GP->observers) - WRITEKEY(fp, TSTRING, "OBSERVER", GP->observers, "Observers"); - // PROG-ID / Observation program identifier - if(GP->prog_id) - WRITEKEY(fp, TSTRING, "PROG-ID", GP->prog_id, "Observation program identifier"); - // AUTHOR / Author of the program - if(GP->author) - WRITEKEY(fp, TSTRING, "AUTHOR", GP->author, "Author of the program"); - // OBJECT / Object name - if(GP->objname){ - WRITEKEY(fp, TSTRING, "OBJECT", GP->objname, "Object name"); - } // FILE / Input file original name char *n = fnam; if(*n == '!') ++n; - WRITEKEY(fp, TSTRING, "FILE", n, "Input file original name"); - // DETECTOR / detector - if(camera->getModelName(buff, PATH_MAX)) - WRITEKEY(fp, TSTRING, "DETECTOR", buff, "Detector model"); - // INSTRUME / Instrument - if(GP->instrument) - WRITEKEY(fp, TSTRING, "INSTRUME", GP->instrument, "Instrument"); + s = 0; fits_write_comment(fp, "Input file original name:", &s); + s = 0; fits_write_comment(fp, n, &s); + //WRITEKEY(fp, TSTRING, "FILE", n, "Input file original name"); if(nbytes == 1) TRYFITS(fits_write_img, fp, TBYTE, 1, width * height, img->data); else TRYFITS(fits_write_img, fp, TUSHORT, 1, width * height, img->data); if(fitserror) goto cloerr; @@ -394,6 +348,7 @@ static void stat16(cc_IMG *image){ void calculate_stat(cc_IMG *image){ + if(!image || image->gotstat) return; int nbytes = ((7 + image->bitpix) / 8); if(nbytes == 1) stat8(image); else stat16(image); @@ -402,6 +357,7 @@ void calculate_stat(cc_IMG *image){ printf("avr = %.1f, std = %.1f\n", image->avr, image->std); printf("max = %u, min = %u, size = %d pix\n", image->max, image->min, image->w * image->h); } + image->gotstat = 1; } cc_Focuser *startFocuser(){ @@ -643,6 +599,19 @@ int prepare_ccds(){ WARNX(_("Can't set active camera number")); goto retn; } + // run plugincmd handler if available + if(GP->plugincmd){ + DBG("Plugincmd"); + if(!camera->plugincmd) WARNX(_("Camera plugin have no custom commands")); + else{ + char **p = GP->plugincmd; + DBG("got %s", *p); + while(p && *p){ + printf("Command: %s\nAnswer: %s\n", *p, camera->plugincmd(*p)); + ++p; + } + } + } if(GP->fanspeed > -1){ if(GP->fanspeed > FAN_HIGH) GP->fanspeed = FAN_HIGH; if(!camera->setfanspeed((cc_fan_speed)GP->fanspeed)) @@ -791,6 +760,7 @@ DBG("w=%d, h=%d", raw_width, raw_height); WARNX(_("Can't grab image")); break; } + ima.gotstat = 0; TIMESTAMP("Calc stat"); calculate_stat(&ima); TIMESTAMP("Save fits"); diff --git a/ccdfunc.h b/ccdfunc.h index a2b57f3..4e46e34 100644 --- a/ccdfunc.h +++ b/ccdfunc.h @@ -24,6 +24,7 @@ extern cc_Focuser *focuser; extern cc_Wheel *wheel; void calculate_stat(cc_IMG *image); +cc_charbuff *getFITSheader(cc_IMG *img); int saveFITS(cc_IMG *img, char **outp); // for imageview module void focusers(); void wheels(); diff --git a/client.c b/client.c index b4d3632..a25bdf6 100644 --- a/client.c +++ b/client.c @@ -32,6 +32,8 @@ #include "server.h" // for common commands names #include "socket.h" +extern double answer_timeout; + static char sendbuf[BUFSIZ]; // send message and wait any answer #define SENDMSG(...) do{DBG("SENDMSG"); snprintf(sendbuf, BUFSIZ-1, __VA_ARGS__); verbose(2, "\t> %s", sendbuf); cc_sendstrmessage(sock, sendbuf); while(getans(sock, NULL));} while(0) @@ -52,17 +54,16 @@ static uint8_t *imbuf = NULL; #endif static char *readmsg(int fd){ - static cc_charbuff *buf = NULL; - static char line[BUFSIZ]; - if(!buf) buf = cc_bufnew(BUFSIZ); + static cc_strbuff *buf = NULL; + if(!buf) buf = cc_strbufnew(BUFSIZ, 255); if(1 == cc_canberead(fd)){ if(cc_read2buf(fd, buf)){ - size_t got = cc_getline(buf, line, BUFSIZ); - if(got >= BUFSIZ){ + size_t got = cc_getline(buf); + if(got > 255){ DBG("Client fd=%d gave buffer overflow", fd); LOGMSG("SERVER client fd=%d buffer overflow", fd); }else if(got){ - return line; + return buf->string; } }else ERRX("Server disconnected"); } @@ -103,7 +104,7 @@ static int parseans(char *ans){ static int getans(int sock, const char *msg){ double t0 = dtime(); char *ans = NULL; - while(dtime() - t0 < CC_ANSWER_TIMEOUT){ + while(dtime() - t0 < answer_timeout){ char *s = readmsg(sock); if(!s) continue; t0 = dtime(); @@ -118,7 +119,6 @@ DBG("1 msg-> %s, ans -> %s", msg, ans); break; } } - //DBG("GETANS: %s, %s", ans, (dtime()-t0 > CC_ANSWER_TIMEOUT) ? "timeout" : "got answer"); return ((ans) ? TRUE : FALSE); } @@ -126,6 +126,9 @@ DBG("1 msg-> %s, ans -> %s", msg, ans); * @brief processData - process here some actions and make messages for server */ static void send_headers(int sock){ + if(GP->exptime > -DBL_EPSILON) SENDMSGW(CC_CMD_EXPOSITION, "=%g", GP->exptime); + DBG("infty=%d", GP->infty); + if(GP->infty > -1) SENDMSGW(CC_CMD_INFTY, "=%d", GP->infty); // common information SENDMSG(CC_CMD_INFO); // focuser @@ -188,7 +191,6 @@ static void send_headers(int sock){ if(!*GP->outfileprefix) SENDMSGW(CC_CMD_FILENAMEPREFIX, "="); else SENDMSGW(CC_CMD_FILENAMEPREFIX, "=%s", makeabspath(GP->outfileprefix, FALSE)); } - if(GP->exptime > -DBL_EPSILON) SENDMSGW(CC_CMD_EXPOSITION, "=%g", GP->exptime); // FITS header keywords: #define CHKHDR(x, cmd) do{if(x) SENDMSG(cmd "=%s", x);}while(0) CHKHDR(GP->author, CC_CMD_AUTHOR); @@ -218,7 +220,6 @@ void client(int sock){ SENDCMDW(CC_CMD_RESTART); return; } - if(GP->infty > -1) SENDMSGW(CC_CMD_INFTY, "=%d", GP->infty); send_headers(sock); double t0 = dtime(), tw = t0; int Nremain = 0, nframe = 1; @@ -278,7 +279,7 @@ void client(int sock){ SENDMSGW(CC_CMD_EXPSTATE, "=%d", CAMERA_CAPTURE); }else{ GP->waitexpend = 0; - timeout = CC_ANSWER_TIMEOUT; // wait for last file name + timeout = answer_timeout; // wait for last file name } } } diff --git a/cmdlnopts.c b/cmdlnopts.c index a237d23..2dcf6fb 100644 --- a/cmdlnopts.c +++ b/cmdlnopts.c @@ -34,19 +34,25 @@ static glob_pars G = { .infty = -1 }; +// need this to proper work with only-long args +//#define NA (-__COUNTER__) +// TODO: fix the bug in usefull_macros first!!! +#define NA (0) + /* * Define command line options by filling structure: * name has_arg flag val type argptr help */ myoption cmdlnopts[] = { - {"plugin" ,NEED_ARG, NULL, 0, arg_string, APTR(&G.commondev), N_("common device plugin (e.g devfli.so)")}, + {"plugin" ,NEED_ARG, NULL, NA, arg_string, APTR(&G.commondev), N_("common device plugin (e.g devfli.so)")}, + {"plugincmd",MULT_PAR, NULL, '_', arg_string, APTR(&G.plugincmd), N_("custom camera device plugin command")}, {"cameradev", NEED_ARG, NULL, 'C', arg_string, APTR(&G.cameradev), N_("camera device plugin (e.g. devfli.so)")}, {"focuserdev", NEED_ARG,NULL, 'F', arg_string, APTR(&G.focuserdev),N_("focuser device plugin (e.g. devzwo.so)")}, {"wheeldev", NEED_ARG, NULL, 'W', arg_string, APTR(&G.wheeldev), N_("wheel device plugin (e.g. devdummy.so)")}, {"list", NO_ARGS, NULL, 'L', arg_int, APTR(&G.listdevices),N_("list connected devices")}, - {"camdevno",NEED_ARG, NULL, 0, arg_int, APTR(&G.camdevno), N_("camera device number (if many: 0, 1, 2 etc)")}, - {"wheeldevno",NEED_ARG, NULL, 0, arg_int, APTR(&G.whldevno), N_("filter wheel device number (if many: 0, 1, 2 etc)")}, - {"focdevno",NEED_ARG, NULL, 0, arg_int, APTR(&G.focdevno), N_("focuser device number (if many: 0, 1, 2 etc)")}, + {"camdevno",NEED_ARG, NULL, NA, arg_int, APTR(&G.camdevno), N_("camera device number (if many: 0, 1, 2 etc)")}, + {"wheeldevno",NEED_ARG, NULL, NA, arg_int, APTR(&G.whldevno), N_("filter wheel device number (if many: 0, 1, 2 etc)")}, + {"focdevno",NEED_ARG, NULL, NA, arg_int, APTR(&G.focdevno), N_("focuser device number (if many: 0, 1, 2 etc)")}, {"help", NO_ARGS, &help, 1, arg_none, NULL, N_("show this help")}, {"rewrite", NO_ARGS, &G.rewrite,1, arg_none, NULL, N_("rewrite output file if exists")}, {"verbose", NO_ARGS, NULL, 'V', arg_none, APTR(&G.verbose), N_("verbose level (-V - messages, -VV - debug, -VVV - all shit)")}, @@ -54,7 +60,7 @@ myoption cmdlnopts[] = { {"8bit", NO_ARGS, NULL, '8', arg_int, APTR(&G._8bit), N_("run in 8-bit mode")}, {"fast", NO_ARGS, NULL, 'f', arg_none, APTR(&G.fast), N_("fast readout mode")}, {"set-temp",NEED_ARG, NULL, 't', arg_double, APTR(&G.temperature),N_("set CCD temperature to given value (degr C)")}, - {"set-fan", NEED_ARG, NULL, 0, arg_int, APTR(&G.fanspeed), N_("set fan speed (0 - off, 1 - low, 2 - high)")}, + {"set-fan", NEED_ARG, NULL, NA, arg_int, APTR(&G.fanspeed), N_("set fan speed (0 - off, 1 - low, 2 - high)")}, {"author", NEED_ARG, NULL, 'A', arg_string, APTR(&G.author), N_("program author")}, {"objtype", NEED_ARG, NULL, 'Y', arg_string, APTR(&G.objtype), N_("object type (neon, object, flat etc)")}, @@ -73,10 +79,10 @@ myoption cmdlnopts[] = { {"pause", NEED_ARG, NULL, 'p', arg_int, APTR(&G.pause_len), N_("make pause for N seconds between expositions")}, {"exptime", NEED_ARG, NULL, 'x', arg_double, APTR(&G.exptime), N_("set exposure time to given value (seconds!)")}, {"cancel", NO_ARGS, &G.cancelexpose, 1,arg_none, NULL, N_("cancel current exposition")}, - {"X0", NEED_ARG, NULL, 0, arg_int, APTR(&G.X0), N_("absolute (not divided by binning!) frame X0 coordinate (-1 - all with overscan)")}, - {"Y0", NEED_ARG, NULL, 0, arg_int, APTR(&G.Y0), N_("absolute frame Y0 coordinate (-1 - all with overscan)")}, - {"X1", NEED_ARG, NULL, 0, arg_int, APTR(&G.X1), N_("absolute frame X1 coordinate (-1 - all with overscan)")}, - {"Y1", NEED_ARG, NULL, 0, arg_int, APTR(&G.Y1), N_("absolute frame Y1 coordinate (-1 - all with overscan)")}, + {"X0", NEED_ARG, NULL, NA, arg_int, APTR(&G.X0), N_("absolute (not divided by binning!) frame X0 coordinate (-1 - all with overscan)")}, + {"Y0", NEED_ARG, NULL, NA, arg_int, APTR(&G.Y0), N_("absolute frame Y0 coordinate (-1 - all with overscan)")}, + {"X1", NEED_ARG, NULL, NA, arg_int, APTR(&G.X1), N_("absolute frame X1 coordinate (-1 - all with overscan)")}, + {"Y1", NEED_ARG, NULL, NA, arg_int, APTR(&G.Y1), N_("absolute frame Y1 coordinate (-1 - all with overscan)")}, {"open-shutter",NO_ARGS,&G.shtr_cmd, SHUTTER_OPEN,arg_none,NULL, N_("open shutter")}, {"close-shutter",NO_ARGS,&G.shtr_cmd, SHUTTER_CLOSE,arg_none,NULL, N_("close shutter")}, @@ -93,20 +99,20 @@ myoption cmdlnopts[] = { {"wheel-set",NEED_ARG, NULL, 'w', arg_int, APTR(&G.setwheel), N_("set wheel position")}, - {"gain", NEED_ARG, NULL, 0, arg_float, APTR(&G.gain), N_("CMOS gain level")}, - {"brightness",NEED_ARG, NULL, 0, arg_float, APTR(&G.brightness),N_("CMOS brightness level")}, + {"gain", NEED_ARG, NULL, NA, arg_float, APTR(&G.gain), N_("CMOS gain level")}, + {"brightness",NEED_ARG, NULL, NA, arg_float, APTR(&G.brightness),N_("CMOS brightness level")}, - {"logfile", NEED_ARG, NULL, 0, arg_string, APTR(&G.logfile), N_("logging file name (if run as server)")}, - {"path", NEED_ARG, NULL, 0, arg_string, APTR(&G.path), N_("UNIX socket name (command socket)")}, - {"port", NEED_ARG, NULL, 0, arg_string, APTR(&G.port), N_("local INET command socket port")}, - {"imageport",NEED_ARG, NULL, 0, arg_string, APTR(&G.imageport), N_("INET image socket port")}, + {"logfile", NEED_ARG, NULL, NA, arg_string, APTR(&G.logfile), N_("logging file name (if run as server)")}, + {"path", NEED_ARG, NULL, NA, arg_string, APTR(&G.path), N_("UNIX socket name (command socket)")}, + {"port", NEED_ARG, NULL, NA, arg_string, APTR(&G.port), N_("local INET command socket port")}, + {"imageport",NEED_ARG, NULL, NA, arg_string, APTR(&G.imageport), N_("INET image socket port")}, {"client", NO_ARGS, &G.client,1, arg_none, NULL, N_("run as client")}, {"viewer", NO_ARGS, &G.viewer,1, arg_none, NULL, N_("passive viewer (only get last images)")}, {"restart", NO_ARGS, &G.restart,1, arg_none, NULL, N_("restart image server")}, {"shmkey", NEED_ARG, NULL, 'k', arg_int, APTR(&G.shmkey), N_("shared memory (with image data) key (default: 7777777)")}, {"forceimsock",NO_ARGS, &G.forceimsock,1, arg_none, NULL, N_("force using image through socket transition even if can use SHM)")}, - {"infty", NEED_ARG, NULL, 0, arg_int, APTR(&G.infty), N_("start (!=0) or stop(==0) infinity capturing loop")}, + {"infty", NEED_ARG, NULL, NA, arg_int, APTR(&G.infty), N_("start (!=0) or stop(==0) infinity capturing loop")}, #ifdef IMAGEVIEW {"display", NO_ARGS, NULL, 'D', arg_int, APTR(&G.showimage), N_("Display image in OpenGL window")}, diff --git a/cmdlnopts.h b/cmdlnopts.h index 3ed6130..66207fc 100644 --- a/cmdlnopts.h +++ b/cmdlnopts.h @@ -40,6 +40,7 @@ typedef struct{ char *port; // local INET socket port char *imageport; // port to send/receive images (by default == port+1) char **addhdr; // list of files from which to add header records + char **plugincmd; // plugin commands int restart; // restart server int waitexpend; // wait while exposition ends int cancelexpose; // cancel exp (for Grasshopper - forbid forever) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f4a403e..53c2310 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.20) include_directories(..) -add_executable(ccd_client main.c) +add_executable(ccd_client ccd_client.c) target_link_libraries(ccd_client ccdcapture usefull_macros) diff --git a/examples/ccd_client.c b/examples/ccd_client.c new file mode 100644 index 0000000..bceeef2 --- /dev/null +++ b/examples/ccd_client.c @@ -0,0 +1,134 @@ +/* + * This file is part of the CCD_Capture project. + * Copyright 2023 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 . + */ + +/* + * A simple example to take 8-bit images with default size and given exposition time. + * Works in `infinity` mode or requesting each file after receiving previous. + */ + +#include +#include +#include + +#include "socket.h" + +typedef struct{ + char *sockname; // UNIX socket name of command socket or port of local socket + int isun; // command socket is UNIX socket instead of INET + int shmkey; // shared memory (with image data) key + int infty; // run in infinity loop (if not - run by requests) + int nframes; // amount of frames to take + int help; // show this help + double exptime; // time of exposition in seconds +} glob_pars; + + +static glob_pars G = { + .shmkey = 7777777, + .nframes = 10 +}; + +/* + * Define command line options by filling structure: + * name has_arg flag val type argptr help +*/ +myoption cmdlnopts[] = { + {"sock", NEED_ARG, NULL, 's', arg_string, APTR(&G.sockname), "command socket name or port"}, + {"isun", NO_ARGS, NULL, 'U', arg_int, APTR(&G.isun), "use UNIX socket"}, + {"shmkey", NEED_ARG, NULL, 'k', arg_int, APTR(&G.shmkey), "shared memory (with image data) key (default: 7777777)"}, + {"infty", NO_ARGS, NULL, 'i', arg_int, APTR(&G.infty), "run in infinity capturing loop (else - request each frame)"}, + {"nframes", NEED_ARG, NULL, 'n', arg_int, APTR(&G.nframes), "make series of N frames"}, + {"exptime", NEED_ARG, NULL, 'x', arg_double, APTR(&G.exptime), "set exposure time to given value (seconds!)"}, + {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&G.help), "show this help"}, +}; + +static cc_IMG *shimg = NULL, img = {0}; + +static int refresh_img(){ + if(!shimg) return FALSE; + static size_t imnumber = 0; + if(shimg->imnumber == imnumber) return FALSE; + imnumber = shimg->imnumber; + void *optr = img.data; + memcpy(&img, shimg, sizeof(img)); + img.data = realloc(optr, img.bytelen); + memcpy(img.data, (uint8_t*)shimg + sizeof(cc_IMG), img.bytelen); + return TRUE; +} + +#define STRBUFSZ (256) + +int main(int argc, char **argv){ + initial_setup(); + parseargs(&argc, &argv, cmdlnopts); + if(G.help) showhelp(-1, cmdlnopts); + if(argc > 0){ + WARNX("%d unused parameters:", argc); + for(int i = 0; i < argc; ++i) + printf("%4d: %s\n", i, argv[i]); + } + if(!G.sockname) ERRX("Point socket name or port"); + cc_strbuff *cbuf = cc_strbufnew(BUFSIZ, STRBUFSZ); + int sock = cc_open_socket(FALSE, G.sockname, !G.isun); + if(sock < 0) ERR("Can't open socket %s", G.sockname); + int shmemkey = 0; + if(RESULT_OK == cc_getint(sock, cbuf, CC_CMD_SHMEMKEY, &shmemkey)){ + green("Got shm key: %d\n", shmemkey); + }else{ + red("Can't read shmkey, try yours\n"); + shmemkey = G.shmkey; + } + if(RESULT_OK == cc_setint(sock, cbuf, CC_CMD_INFTY, 1)) green("ask for INFTY\n"); + else red("Can't ask for INFTY\n"); + float xt = 0.f; + if(RESULT_OK == cc_getfloat(sock, cbuf, CC_CMD_EXPOSITION, &xt)){ + green("Old exp time: %gs\n", xt); + } + fflush(stdout); + if(RESULT_OK == cc_setfloat(sock, cbuf, CC_CMD_EXPOSITION, 0.5)) green("ask for exptime 0.5s\n"); + else red("Can't change exptime to 0.5s\n"); + shimg = cc_getshm(shmemkey, 0); + if(!shimg) ERRX("Can't get shared memory segment"); + int i = 0; + time_t oldtime = time(NULL); + double oldtimestamp = shimg->timestamp; + do{ + if(cc_refreshbuf(sock, cbuf) && cc_getline(cbuf)){ + printf("\t\tServer sent: `%s`\n", cbuf->string); + } + time_t now = time(NULL); + if(now - oldtime > 5){ + WARNX("No new images for 5 seconds"); + break; + } + if(!refresh_img()){ + usleep(1000); + continue; + } + ++i; + oldtime = now; + printf("Got image #%zd, size %dx%d, bitpix %d, time %g\n", img.imnumber, img.w, img.h, img.bitpix, img.timestamp-oldtimestamp); + }while(i < 2); + if(RESULT_OK != cc_setint(sock, cbuf, CC_CMD_INFTY, 0)) red("Can't clear INFTY\n"); + if(xt > 0.){ + if(RESULT_OK != cc_setfloat(sock, cbuf, CC_CMD_EXPOSITION, xt)) red("Can't return exptime to %gs\n", xt); + } + cc_strbufdel(&cbuf); + close(sock); + return 0; +} diff --git a/locale/ru/messages.po b/locale/ru/messages.po index 04646b0..72ee692 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: 2024-01-24 11:37+0300\n" +"POT-Creation-Date: 2024-02-01 14:36+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,545 +17,553 @@ msgstr "" "Content-Type: text/plain; charset=koi8-r\n" "Content-Transfer-Encoding: 8bit\n" -#: cmdlnopts.c:42 +#: cmdlnopts.c:47 msgid "common device plugin (e.g devfli.so)" msgstr "" -#: cmdlnopts.c:43 -msgid "camera device plugin (e.g. devfli.so)" -msgstr "" - -#: cmdlnopts.c:44 -msgid "focuser device plugin (e.g. devzwo.so)" -msgstr "" - -#: cmdlnopts.c:45 -msgid "wheel device plugin (e.g. devdummy.so)" -msgstr "" - -#: cmdlnopts.c:46 -msgid "list connected devices" -msgstr "" - -#: cmdlnopts.c:47 -msgid "camera device number (if many: 0, 1, 2 etc)" -msgstr "" - #: cmdlnopts.c:48 -msgid "filter wheel device number (if many: 0, 1, 2 etc)" +msgid "custom camera device plugin command" msgstr "" #: cmdlnopts.c:49 -msgid "focuser device number (if many: 0, 1, 2 etc)" +msgid "camera device plugin (e.g. devfli.so)" msgstr "" #: cmdlnopts.c:50 -msgid "show this help" +msgid "focuser device plugin (e.g. devzwo.so)" msgstr "" #: cmdlnopts.c:51 -msgid "rewrite output file if exists" +msgid "wheel device plugin (e.g. devdummy.so)" msgstr "" #: cmdlnopts.c:52 -msgid "verbose level (-V - messages, -VV - debug, -VVV - all shit)" +msgid "list connected devices" msgstr "" #: cmdlnopts.c:53 -msgid "not open shutter, when exposing (\"dark frames\")" +msgid "camera device number (if many: 0, 1, 2 etc)" msgstr "" #: cmdlnopts.c:54 -msgid "run in 8-bit mode" +msgid "filter wheel device number (if many: 0, 1, 2 etc)" msgstr "" #: cmdlnopts.c:55 -msgid "fast readout mode" +msgid "focuser device number (if many: 0, 1, 2 etc)" msgstr "" #: cmdlnopts.c:56 -msgid "set CCD temperature to given value (degr C)" +msgid "show this help" msgstr "" #: cmdlnopts.c:57 -msgid "set fan speed (0 - off, 1 - low, 2 - high)" +msgid "rewrite output file if exists" +msgstr "" + +#: cmdlnopts.c:58 +msgid "verbose level (-V - messages, -VV - debug, -VVV - all shit)" msgstr "" #: cmdlnopts.c:59 -msgid "program author" +msgid "not open shutter, when exposing (\"dark frames\")" msgstr "" #: cmdlnopts.c:60 -msgid "object type (neon, object, flat etc)" +msgid "run in 8-bit mode" msgstr "" #: cmdlnopts.c:61 -msgid "instrument name" +msgid "fast readout mode" msgstr "" #: cmdlnopts.c:62 -msgid "object name" +msgid "set CCD temperature to given value (degr C)" msgstr "" #: cmdlnopts.c:63 -msgid "observers' names" -msgstr "" - -#: cmdlnopts.c:64 -msgid "observing program name" +msgid "set fan speed (0 - off, 1 - low, 2 - high)" msgstr "" #: cmdlnopts.c:65 -msgid "add records to header from given file[s]" +msgid "program author" msgstr "" #: cmdlnopts.c:66 -msgid "output file name" +msgid "object type (neon, object, flat etc)" msgstr "" #: cmdlnopts.c:67 -msgid "wait while exposition ends" +msgid "instrument name" +msgstr "" + +#: cmdlnopts.c:68 +msgid "object name" msgstr "" #: cmdlnopts.c:69 -msgid "N flushes before exposing (default: 1)" +msgid "observers' names" msgstr "" #: cmdlnopts.c:70 -msgid "horizontal binning to N pixels" +msgid "observing program name" msgstr "" #: cmdlnopts.c:71 -msgid "vertical binning to N pixels" +msgid "add records to header from given file[s]" msgstr "" #: cmdlnopts.c:72 -msgid "make series of N frames" +msgid "output file name" msgstr "" #: cmdlnopts.c:73 -msgid "make pause for N seconds between expositions" -msgstr "" - -#: cmdlnopts.c:74 -msgid "set exposure time to given value (seconds!)" +msgid "wait while exposition ends" msgstr "" #: cmdlnopts.c:75 -msgid "cancel current exposition" +msgid "N flushes before exposing (default: 1)" msgstr "" #: cmdlnopts.c:76 +msgid "horizontal binning to N pixels" +msgstr "" + +#: cmdlnopts.c:77 +msgid "vertical binning to N pixels" +msgstr "" + +#: cmdlnopts.c:78 +msgid "make series of N frames" +msgstr "" + +#: cmdlnopts.c:79 +msgid "make pause for N seconds between expositions" +msgstr "" + +#: cmdlnopts.c:80 +msgid "set exposure time to given value (seconds!)" +msgstr "" + +#: cmdlnopts.c:81 +msgid "cancel current exposition" +msgstr "" + +#: cmdlnopts.c:82 msgid "" "absolute (not divided by binning!) frame X0 coordinate (-1 - all with " "overscan)" msgstr "" -#: cmdlnopts.c:77 +#: cmdlnopts.c:83 msgid "absolute frame Y0 coordinate (-1 - all with overscan)" msgstr "" -#: cmdlnopts.c:78 +#: cmdlnopts.c:84 msgid "absolute frame X1 coordinate (-1 - all with overscan)" msgstr "" -#: cmdlnopts.c:79 +#: cmdlnopts.c:85 msgid "absolute frame Y1 coordinate (-1 - all with overscan)" msgstr "" -#: cmdlnopts.c:81 +#: cmdlnopts.c:87 msgid "open shutter" msgstr "" -#: cmdlnopts.c:82 +#: cmdlnopts.c:88 msgid "close shutter" msgstr "" -#: cmdlnopts.c:83 +#: cmdlnopts.c:89 msgid "run exposition on LOW @ pin5 I/O port" msgstr "" -#: cmdlnopts.c:84 +#: cmdlnopts.c:90 msgid "run exposition on HIGH @ pin5 I/O port" msgstr "" -#: cmdlnopts.c:85 +#: cmdlnopts.c:91 msgid "get value of I/O port pins" msgstr "" -#: cmdlnopts.c:86 +#: cmdlnopts.c:92 msgid "move stepper motor asynchronous" msgstr "" -#: cmdlnopts.c:88 +#: cmdlnopts.c:94 msgid "set I/O port pins to given value (decimal number, pin1 is LSB)" msgstr "" -#: cmdlnopts.c:89 +#: cmdlnopts.c:95 msgid "" "configure I/O port pins to given value (decimal number, pin1 is LSB, 1 == " "output, 0 == input)" msgstr "" -#: cmdlnopts.c:91 +#: cmdlnopts.c:97 msgid "move focuser to absolute position, mm" msgstr "" -#: cmdlnopts.c:92 +#: cmdlnopts.c:98 msgid "move focuser to relative position, mm (only for standalone)" msgstr "" -#: cmdlnopts.c:94 +#: cmdlnopts.c:100 msgid "set wheel position" msgstr "" -#: cmdlnopts.c:96 +#: cmdlnopts.c:102 msgid "CMOS gain level" msgstr "" -#: cmdlnopts.c:97 +#: cmdlnopts.c:103 msgid "CMOS brightness level" msgstr "" -#: cmdlnopts.c:99 +#: cmdlnopts.c:105 msgid "logging file name (if run as server)" msgstr "" -#: cmdlnopts.c:100 +#: cmdlnopts.c:106 msgid "UNIX socket name (command socket)" msgstr "" -#: cmdlnopts.c:101 +#: cmdlnopts.c:107 msgid "local INET command socket port" msgstr "" -#: cmdlnopts.c:102 +#: cmdlnopts.c:108 msgid "INET image socket port" msgstr "" -#: cmdlnopts.c:103 +#: cmdlnopts.c:109 msgid "run as client" msgstr "" -#: cmdlnopts.c:104 +#: cmdlnopts.c:110 msgid "passive viewer (only get last images)" msgstr "" -#: cmdlnopts.c:105 +#: cmdlnopts.c:111 msgid "restart image server" msgstr "" -#: cmdlnopts.c:107 +#: cmdlnopts.c:113 msgid "shared memory (with image data) key (default: 7777777)" msgstr "" -#: cmdlnopts.c:108 +#: cmdlnopts.c:114 msgid "force using image through socket transition even if can use SHM)" msgstr "" -#: cmdlnopts.c:109 +#: cmdlnopts.c:115 msgid "start (!=0) or stop(==0) infinity capturing loop" msgstr "" -#: cmdlnopts.c:112 +#: cmdlnopts.c:118 msgid "Display image in OpenGL window" msgstr "" -#: ccdfunc.c:138 +#: ccdfunc.c:197 msgid "Camera device unknown" msgstr "" #. Не могу сохранить файл -#: ccdfunc.c:162 +#: ccdfunc.c:221 #, c-format msgid "Can't save file with prefix %s" msgstr "" -#: ccdfunc.c:315 +#: ccdfunc.c:269 #, c-format msgid "File saved as '%s'" msgstr "" -#: ccdfunc.c:324 +#: ccdfunc.c:278 msgid "Error saving file" msgstr "" -#: ccdfunc.c:401 +#: ccdfunc.c:356 #, c-format msgid "Image stat:\n" msgstr "" -#: ccdfunc.c:409 +#: ccdfunc.c:365 msgid "Focuser device not pointed" msgstr "" -#: ccdfunc.c:416 +#: ccdfunc.c:372 msgid "No focusers found" msgstr "" -#: ccdfunc.c:447 +#: ccdfunc.c:403 #, c-format msgid "Found %d focusers, you point number %d" msgstr "" -#: ccdfunc.c:451 +#: ccdfunc.c:407 msgid "Can't set active focuser number" msgstr "" -#: ccdfunc.c:465 +#: ccdfunc.c:421 msgid "Can't get focuser limit positions" msgstr "" -#: ccdfunc.c:472 +#: ccdfunc.c:428 msgid "Can't get current focuser position" msgstr "" -#: ccdfunc.c:486 +#: ccdfunc.c:442 #, c-format msgid "Can't set position %g: out of limits [%g, %g]" msgstr "" -#: ccdfunc.c:490 +#: ccdfunc.c:446 msgid "Can't home focuser" msgstr "" -#: ccdfunc.c:492 +#: ccdfunc.c:448 #, c-format msgid "Can't set position %g" msgstr "" -#: ccdfunc.c:500 +#: ccdfunc.c:456 msgid "cc_Wheel device not pointed" msgstr "" -#: ccdfunc.c:507 +#: ccdfunc.c:463 msgid "No wheels found" msgstr "" -#: ccdfunc.c:538 +#: ccdfunc.c:494 #, c-format msgid "Found %d wheels, you point number %d" msgstr "" -#: ccdfunc.c:542 +#: ccdfunc.c:498 msgid "Can't set active wheel number" msgstr "" -#: ccdfunc.c:558 +#: ccdfunc.c:514 msgid "Can't get max wheel position" msgstr "" -#: ccdfunc.c:565 +#: ccdfunc.c:521 #, c-format msgid "cc_Wheel position should be from 0 to %d" msgstr "" -#: ccdfunc.c:569 +#: ccdfunc.c:525 #, c-format msgid "Can't set wheel position %d" msgstr "" -#: ccdfunc.c:586 +#: ccdfunc.c:542 #, c-format msgid "%.1f seconds till exposition ends" msgstr "" -#: ccdfunc.c:601 +#: ccdfunc.c:557 msgid "Camera device not pointed" msgstr "" -#: ccdfunc.c:608 ccdfunc.c:609 +#: ccdfunc.c:564 ccdfunc.c:565 msgid "No cameras found" msgstr "" -#: ccdfunc.c:639 +#: ccdfunc.c:595 #, c-format msgid "Found %d cameras, you point number %d" msgstr "" -#: ccdfunc.c:643 +#: ccdfunc.c:599 msgid "Can't set active camera number" msgstr "" -#: ccdfunc.c:649 +#: ccdfunc.c:605 +msgid "Camera plugin have no custom commands" +msgstr "" + +#: ccdfunc.c:618 msgid "Can't set fan speed" msgstr "" -#: ccdfunc.c:650 +#: ccdfunc.c:619 #, c-format msgid "Set fan speed to %d" msgstr "" -#: ccdfunc.c:655 +#: ccdfunc.c:624 #, c-format msgid "Camera model: %s" msgstr "" -#: ccdfunc.c:656 +#: ccdfunc.c:625 #, c-format msgid "Pixel size: %g x %g" msgstr "" -#: ccdfunc.c:662 +#: ccdfunc.c:631 #, c-format msgid "Full array: %s" msgstr "" -#: ccdfunc.c:665 +#: ccdfunc.c:634 #, c-format msgid "Field of view: %s" msgstr "" -#: ccdfunc.c:668 +#: ccdfunc.c:637 #, c-format msgid "Current format: %s" msgstr "" -#: ccdfunc.c:671 +#: ccdfunc.c:640 #, c-format msgid "Can't set T to %g degC" msgstr "" -#: ccdfunc.c:679 +#: ccdfunc.c:648 #, c-format msgid "Shutter command: %s\n" msgstr "" -#: ccdfunc.c:681 +#: ccdfunc.c:650 #, c-format msgid "Can't run shutter command %s (unsupported?)" msgstr "" #. "Попытка сконфигурировать порт I/O как %d\n" -#: ccdfunc.c:685 +#: ccdfunc.c:654 #, c-format msgid "Try to configure I/O port as %d" msgstr "" -#: ccdfunc.c:687 +#: ccdfunc.c:656 msgid "Can't configure (unsupported?)" msgstr "" -#: ccdfunc.c:694 +#: ccdfunc.c:663 msgid "Can't get IOport state (unsupported?)" msgstr "" #. "Попытка записи %d в порт I/O\n" -#: ccdfunc.c:698 +#: ccdfunc.c:667 #, c-format msgid "Try to write %d to I/O port" msgstr "" -#: ccdfunc.c:700 +#: ccdfunc.c:669 msgid "Can't set IOport" msgstr "" -#: ccdfunc.c:707 +#: ccdfunc.c:676 #, c-format msgid "Set gain to %g" msgstr "" -#: ccdfunc.c:708 +#: ccdfunc.c:677 #, c-format msgid "Can't set gain to %g" msgstr "" -#: ccdfunc.c:713 +#: ccdfunc.c:682 #, c-format msgid "Set brightness to %g" msgstr "" -#: ccdfunc.c:714 +#: ccdfunc.c:683 #, c-format msgid "Can't set brightness to %g" msgstr "" -#: ccdfunc.c:720 server.c:264 +#: ccdfunc.c:689 server.c:265 #, c-format msgid "Can't set binning %dx%d" msgstr "" -#: ccdfunc.c:732 server.c:265 +#: ccdfunc.c:701 server.c:266 msgid "Can't set given geometry" msgstr "" -#: ccdfunc.c:736 +#: ccdfunc.c:705 #, c-format msgid "Can't set %d flushes" msgstr "" -#: ccdfunc.c:740 +#: ccdfunc.c:709 #, c-format msgid "Can't set exposure time to %f seconds" msgstr "" -#: ccdfunc.c:743 +#: ccdfunc.c:712 msgid "Can't change frame type" msgstr "" -#: ccdfunc.c:746 +#: ccdfunc.c:715 msgid "Can't set bit depth" msgstr "" -#: ccdfunc.c:748 +#: ccdfunc.c:717 msgid "Can't set readout speed" msgstr "" -#: ccdfunc.c:749 +#: ccdfunc.c:718 #, c-format msgid "Readout mode: %s" msgstr "" -#: ccdfunc.c:750 +#: ccdfunc.c:719 msgid "Only show statistics" msgstr "" #. GET binning should be AFTER setgeometry! -#: ccdfunc.c:752 +#: ccdfunc.c:721 msgid "Can't get current binning" msgstr "" #. Захват кадра %d\n -#: ccdfunc.c:777 +#: ccdfunc.c:746 #, c-format msgid "Capture frame %d" msgstr "" -#: ccdfunc.c:779 ccdfunc.c:853 server.c:148 +#: ccdfunc.c:748 ccdfunc.c:823 server.c:150 msgid "Can't start exposition" msgstr "" -#: ccdfunc.c:784 +#: ccdfunc.c:753 msgid "Can't capture image" msgstr "" -#: ccdfunc.c:787 +#: ccdfunc.c:756 msgid "Read grabbed image" msgstr "" -#: ccdfunc.c:791 ccdfunc.c:866 +#: ccdfunc.c:760 ccdfunc.c:836 msgid "Can't grab image" msgstr "" #. %d секунд до окончания паузы\n -#: ccdfunc.c:803 client.c:270 +#: ccdfunc.c:773 client.c:271 #, c-format msgid "%d seconds till pause ends\n" msgstr "" -#: ccdfunc.c:864 +#: ccdfunc.c:834 msgid "Some error when capture" msgstr "" -#: server.c:188 +#: server.c:189 msgid "No camera device" msgstr "" -#: client.c:255 +#: client.c:256 msgid "Can't make exposition" msgstr "" -#: client.c:286 +#: client.c:287 msgid "Server timeout" msgstr "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index b01c785..2911dad 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: 2024-01-24 11:35+0300\n" + "POT-Creation-Date: 2024-02-01 14:35+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,13 +16,13 @@ msgstr "Project-Id-Version: PACKAGE VERSION\n" "Content-Type: text/plain; charset=koi8-r\n" "Content-Transfer-Encoding: 8bit\n" -#: ccdfunc.c:586 +#: ccdfunc.c:542 #, c-format msgid "%.1f seconds till exposition ends" msgstr "%.1f " #. %d секунд до окончания паузы\n -#: ccdfunc.c:803 client.c:270 +#: ccdfunc.c:773 client.c:271 #, c-format msgid "%d seconds till pause ends\n" msgstr "%d \n" @@ -31,65 +31,69 @@ msgstr "%d msgid "Already initialized!" msgstr " !" -#: cmdlnopts.c:97 +#: cmdlnopts.c:103 msgid "CMOS brightness level" msgstr " CMOS" -#: cmdlnopts.c:96 +#: cmdlnopts.c:102 msgid "CMOS gain level" msgstr " Gain CMOS" -#: ccdfunc.c:601 +#: ccdfunc.c:557 msgid "Camera device not pointed" msgstr " " -#: ccdfunc.c:138 +#: ccdfunc.c:197 msgid "Camera device unknown" msgstr " " -#: ccdfunc.c:655 +#: ccdfunc.c:624 #, c-format msgid "Camera model: %s" msgstr " : %s" -#: ccdfunc.c:784 +#: ccdfunc.c:605 +msgid "Camera plugin have no custom commands" +msgstr "" + +#: ccdfunc.c:753 msgid "Can't capture image" msgstr " " -#: ccdfunc.c:743 +#: ccdfunc.c:712 msgid "Can't change frame type" msgstr " " -#: ccdfunc.c:687 +#: ccdfunc.c:656 msgid "Can't configure (unsupported?)" msgstr " ( ?)" -#: ccdfunc.c:694 +#: ccdfunc.c:663 msgid "Can't get IOport state (unsupported?)" msgstr " I/O ( ?)" #. GET binning should be AFTER setgeometry! -#: ccdfunc.c:752 +#: ccdfunc.c:721 msgid "Can't get current binning" msgstr " " -#: ccdfunc.c:472 +#: ccdfunc.c:428 msgid "Can't get current focuser position" msgstr " " -#: ccdfunc.c:465 +#: ccdfunc.c:421 msgid "Can't get focuser limit positions" msgstr " " -#: ccdfunc.c:558 +#: ccdfunc.c:514 msgid "Can't get max wheel position" msgstr " " -#: ccdfunc.c:791 ccdfunc.c:866 +#: ccdfunc.c:760 ccdfunc.c:836 msgid "Can't grab image" msgstr " " -#: ccdfunc.c:490 +#: ccdfunc.c:446 msgid "Can't home focuser" msgstr " " @@ -97,7 +101,7 @@ msgstr " msgid "Can't init mutex!" msgstr " !" -#: client.c:255 +#: client.c:256 msgid "Can't make exposition" msgstr " " @@ -105,110 +109,110 @@ msgstr " msgid "Can't open OpenGL window, image preview will be inaccessible" msgstr " OpenGL, " -#: ccdfunc.c:681 +#: ccdfunc.c:650 #, c-format msgid "Can't run shutter command %s (unsupported?)" msgstr " %s ( ?)" #. Не могу сохранить файл -#: ccdfunc.c:162 +#: ccdfunc.c:221 #, c-format msgid "Can't save file with prefix %s" msgstr " %s" -#: ccdfunc.c:736 +#: ccdfunc.c:705 #, c-format msgid "Can't set %d flushes" msgstr " %d " -#: ccdfunc.c:700 +#: ccdfunc.c:669 msgid "Can't set IOport" msgstr " I/O" -#: ccdfunc.c:671 +#: ccdfunc.c:640 #, c-format msgid "Can't set T to %g degC" msgstr " %g " -#: ccdfunc.c:643 +#: ccdfunc.c:599 msgid "Can't set active camera number" msgstr " " -#: ccdfunc.c:451 +#: ccdfunc.c:407 msgid "Can't set active focuser number" msgstr " " -#: ccdfunc.c:542 +#: ccdfunc.c:498 msgid "Can't set active wheel number" msgstr " " -#: ccdfunc.c:720 server.c:264 +#: ccdfunc.c:689 server.c:265 #, c-format msgid "Can't set binning %dx%d" msgstr " %dx%d" -#: ccdfunc.c:746 +#: ccdfunc.c:715 msgid "Can't set bit depth" msgstr " " -#: ccdfunc.c:714 +#: ccdfunc.c:683 #, c-format msgid "Can't set brightness to %g" msgstr " %g" -#: ccdfunc.c:740 +#: ccdfunc.c:709 #, c-format msgid "Can't set exposure time to %f seconds" msgstr " %f " -#: ccdfunc.c:649 +#: ccdfunc.c:618 msgid "Can't set fan speed" msgstr " " -#: ccdfunc.c:708 +#: ccdfunc.c:677 #, c-format msgid "Can't set gain to %g" msgstr " Gain %g" -#: ccdfunc.c:732 server.c:265 +#: ccdfunc.c:701 server.c:266 msgid "Can't set given geometry" msgstr " " -#: ccdfunc.c:492 +#: ccdfunc.c:448 #, c-format msgid "Can't set position %g" msgstr " %g" -#: ccdfunc.c:486 +#: ccdfunc.c:442 #, c-format msgid "Can't set position %g: out of limits [%g, %g]" msgstr " %g: [%g, %g]" -#: ccdfunc.c:748 +#: ccdfunc.c:717 msgid "Can't set readout speed" msgstr " " -#: ccdfunc.c:569 +#: ccdfunc.c:525 #, c-format msgid "Can't set wheel position %d" msgstr " %d" -#: ccdfunc.c:779 ccdfunc.c:853 server.c:148 +#: ccdfunc.c:748 ccdfunc.c:823 server.c:150 msgid "Can't start exposition" msgstr " " #. Захват кадра %d\n -#: ccdfunc.c:777 +#: ccdfunc.c:746 #, c-format msgid "Capture frame %d" msgstr " %d" -#: ccdfunc.c:668 +#: ccdfunc.c:637 #, c-format msgid "Current format: %s" msgstr "" -#: cmdlnopts.c:112 +#: cmdlnopts.c:118 msgid "Display image in OpenGL window" msgstr " OpenGL" @@ -217,40 +221,40 @@ msgstr " msgid "Equalization of histogram: %s" msgstr " : %s" -#: ccdfunc.c:324 +#: ccdfunc.c:278 msgid "Error saving file" msgstr " " -#: ccdfunc.c:665 +#: ccdfunc.c:634 #, c-format msgid "Field of view: %s" msgstr " : %s" -#: ccdfunc.c:315 +#: ccdfunc.c:269 #, c-format msgid "File saved as '%s'" msgstr " '%s'" -#: ccdfunc.c:409 +#: ccdfunc.c:365 msgid "Focuser device not pointed" msgstr " " -#: ccdfunc.c:639 +#: ccdfunc.c:595 #, c-format msgid "Found %d cameras, you point number %d" msgstr " %d , %d" -#: ccdfunc.c:447 +#: ccdfunc.c:403 #, c-format msgid "Found %d focusers, you point number %d" msgstr " %d , %d" -#: ccdfunc.c:538 +#: ccdfunc.c:494 #, c-format msgid "Found %d wheels, you point number %d" msgstr " %d , %d" -#: ccdfunc.c:662 +#: ccdfunc.c:631 #, c-format msgid "Full array: %s" msgstr " : %s" @@ -260,240 +264,245 @@ msgstr " msgid "Histogram conversion: %s" msgstr " : %s" -#: cmdlnopts.c:102 +#: cmdlnopts.c:108 #, fuzzy msgid "INET image socket port" msgstr " " -#: ccdfunc.c:401 +#: ccdfunc.c:356 #, c-format msgid "Image stat:\n" msgstr " : \n" -#: cmdlnopts.c:69 +#: cmdlnopts.c:75 msgid "N flushes before exposing (default: 1)" msgstr "N ( : 1)" -#: server.c:188 +#: server.c:189 msgid "No camera device" msgstr " " -#: ccdfunc.c:608 ccdfunc.c:609 +#: ccdfunc.c:564 ccdfunc.c:565 msgid "No cameras found" msgstr " " -#: ccdfunc.c:416 +#: ccdfunc.c:372 msgid "No focusers found" msgstr " " -#: ccdfunc.c:507 +#: ccdfunc.c:463 msgid "No wheels found" msgstr " " -#: ccdfunc.c:750 +#: ccdfunc.c:719 msgid "Only show statistics" msgstr " " -#: ccdfunc.c:656 +#: ccdfunc.c:625 #, c-format msgid "Pixel size: %g x %g" msgstr " : %g x %g" -#: ccdfunc.c:787 +#: ccdfunc.c:756 msgid "Read grabbed image" msgstr " " -#: ccdfunc.c:749 +#: ccdfunc.c:718 #, c-format msgid "Readout mode: %s" msgstr " : %s" -#: client.c:286 +#: client.c:287 msgid "Server timeout" msgstr " " -#: ccdfunc.c:713 +#: ccdfunc.c:682 #, c-format msgid "Set brightness to %g" msgstr " %g" -#: ccdfunc.c:650 +#: ccdfunc.c:619 #, c-format msgid "Set fan speed to %d" msgstr " %d" -#: ccdfunc.c:707 +#: ccdfunc.c:676 #, c-format msgid "Set gain to %g" msgstr " Gain %g" -#: ccdfunc.c:679 +#: ccdfunc.c:648 #, c-format msgid "Shutter command: %s\n" msgstr " : %s\n" -#: ccdfunc.c:864 +#: ccdfunc.c:834 msgid "Some error when capture" msgstr "" #. "Попытка сконфигурировать порт I/O как %d\n" -#: ccdfunc.c:685 +#: ccdfunc.c:654 #, c-format msgid "Try to configure I/O port as %d" msgstr " I/O %d" #. "Попытка записи %d в порт I/O\n" -#: ccdfunc.c:698 +#: ccdfunc.c:667 #, c-format msgid "Try to write %d to I/O port" msgstr " %d I/O" -#: cmdlnopts.c:100 +#: cmdlnopts.c:106 #, fuzzy msgid "UNIX socket name (command socket)" msgstr " UNIX-" -#: cmdlnopts.c:76 +#: cmdlnopts.c:82 msgid "absolute (not divided by binning!) frame X0 coordinate (-1 - all " "with overscan)" msgstr " ( !) X0 (-1 - " ")" -#: cmdlnopts.c:78 +#: cmdlnopts.c:84 msgid "absolute frame X1 coordinate (-1 - all with overscan)" msgstr " X1 (-1 - )" -#: cmdlnopts.c:77 +#: cmdlnopts.c:83 msgid "absolute frame Y0 coordinate (-1 - all with overscan)" msgstr " Y0 (-1 - )" -#: cmdlnopts.c:79 +#: cmdlnopts.c:85 msgid "absolute frame Y1 coordinate (-1 - all with overscan)" msgstr " Y1 (-1 - )" -#: cmdlnopts.c:65 +#: cmdlnopts.c:71 msgid "add records to header from given file[s]" msgstr " FITS- " -#: cmdlnopts.c:47 +#: cmdlnopts.c:53 msgid "camera device number (if many: 0, 1, 2 etc)" msgstr " " -#: cmdlnopts.c:43 +#: cmdlnopts.c:49 msgid "camera device plugin (e.g. devfli.so)" msgstr " (, devfli.so)" -#: cmdlnopts.c:75 +#: cmdlnopts.c:81 msgid "cancel current exposition" msgstr " " -#: ccdfunc.c:500 +#: ccdfunc.c:456 #, fuzzy msgid "cc_Wheel device not pointed" msgstr " " -#: ccdfunc.c:565 +#: ccdfunc.c:521 #, fuzzy, c-format msgid "cc_Wheel position should be from 0 to %d" msgstr " 0 %d" -#: cmdlnopts.c:82 +#: cmdlnopts.c:88 msgid "close shutter" msgstr " " -#: cmdlnopts.c:42 +#: cmdlnopts.c:47 msgid "common device plugin (e.g devfli.so)" msgstr " (, devfli.so)" -#: cmdlnopts.c:89 +#: cmdlnopts.c:95 msgid "configure I/O port pins to given value (decimal number, pin1 is LSB, " "1 == output, 0 == input)" msgstr " I/O ( , " "pin1 - , 1 - , 0 - )" -#: cmdlnopts.c:55 +#: cmdlnopts.c:48 +#, fuzzy +msgid "custom camera device plugin command" +msgstr " (, devfli.so)" + +#: cmdlnopts.c:61 msgid "fast readout mode" msgstr " " -#: cmdlnopts.c:48 +#: cmdlnopts.c:54 msgid "filter wheel device number (if many: 0, 1, 2 etc)" msgstr " " -#: cmdlnopts.c:49 +#: cmdlnopts.c:55 msgid "focuser device number (if many: 0, 1, 2 etc)" msgstr " " -#: cmdlnopts.c:44 +#: cmdlnopts.c:50 msgid "focuser device plugin (e.g. devzwo.so)" msgstr " (, devzwo.so)" -#: cmdlnopts.c:108 +#: cmdlnopts.c:114 msgid "force using image through socket transition even if can use SHM)" msgstr "" -#: cmdlnopts.c:85 +#: cmdlnopts.c:91 msgid "get value of I/O port pins" msgstr " I/O" -#: cmdlnopts.c:70 +#: cmdlnopts.c:76 msgid "horizontal binning to N pixels" msgstr " N " -#: cmdlnopts.c:61 +#: cmdlnopts.c:67 msgid "instrument name" msgstr " " -#: cmdlnopts.c:46 +#: cmdlnopts.c:52 msgid "list connected devices" msgstr " " -#: cmdlnopts.c:101 +#: cmdlnopts.c:107 #, fuzzy msgid "local INET command socket port" msgstr " " -#: cmdlnopts.c:99 +#: cmdlnopts.c:105 msgid "logging file name (if run as server)" msgstr " ( )" -#: cmdlnopts.c:73 +#: cmdlnopts.c:79 msgid "make pause for N seconds between expositions" msgstr " N " -#: cmdlnopts.c:72 +#: cmdlnopts.c:78 msgid "make series of N frames" msgstr " N " -#: cmdlnopts.c:91 +#: cmdlnopts.c:97 msgid "move focuser to absolute position, mm" msgstr " , " -#: cmdlnopts.c:92 +#: cmdlnopts.c:98 msgid "move focuser to relative position, mm (only for standalone)" msgstr " , ( /" ")" -#: cmdlnopts.c:86 +#: cmdlnopts.c:92 msgid "move stepper motor asynchronous" msgstr " " -#: cmdlnopts.c:53 +#: cmdlnopts.c:59 msgid "not open shutter, when exposing (\"dark frames\")" msgstr " (\"\")" -#: cmdlnopts.c:62 +#: cmdlnopts.c:68 msgid "object name" msgstr " " -#: cmdlnopts.c:60 +#: cmdlnopts.c:66 msgid "object type (neon, object, flat etc)" msgstr " (neon, object, flat ..)" -#: cmdlnopts.c:63 +#: cmdlnopts.c:69 msgid "observers' names" msgstr " " -#: cmdlnopts.c:64 +#: cmdlnopts.c:70 msgid "observing program name" msgstr " " @@ -505,91 +514,91 @@ msgstr " msgid "on" msgstr "" -#: cmdlnopts.c:81 +#: cmdlnopts.c:87 msgid "open shutter" msgstr " " -#: cmdlnopts.c:66 +#: cmdlnopts.c:72 msgid "output file name" msgstr " " -#: cmdlnopts.c:104 +#: cmdlnopts.c:110 msgid "passive viewer (only get last images)" msgstr "" -#: cmdlnopts.c:59 +#: cmdlnopts.c:65 msgid "program author" msgstr " " -#: cmdlnopts.c:105 +#: cmdlnopts.c:111 msgid "restart image server" msgstr " " -#: cmdlnopts.c:51 +#: cmdlnopts.c:57 msgid "rewrite output file if exists" msgstr " " -#: cmdlnopts.c:103 +#: cmdlnopts.c:109 msgid "run as client" msgstr " " -#: cmdlnopts.c:84 +#: cmdlnopts.c:90 msgid "run exposition on HIGH @ pin5 I/O port" msgstr "" -#: cmdlnopts.c:83 +#: cmdlnopts.c:89 msgid "run exposition on LOW @ pin5 I/O port" msgstr "" -#: cmdlnopts.c:54 +#: cmdlnopts.c:60 msgid "run in 8-bit mode" msgstr "8- " -#: cmdlnopts.c:56 +#: cmdlnopts.c:62 msgid "set CCD temperature to given value (degr C)" msgstr " ()" -#: cmdlnopts.c:88 +#: cmdlnopts.c:94 msgid "set I/O port pins to given value (decimal number, pin1 is LSB)" msgstr " I/O ( , pin1 - )" -#: cmdlnopts.c:74 +#: cmdlnopts.c:80 msgid "set exposure time to given value (seconds!)" msgstr " (!)" -#: cmdlnopts.c:57 +#: cmdlnopts.c:63 msgid "set fan speed (0 - off, 1 - low, 2 - high)" msgstr " (0 - , 1 - , 2 - )" -#: cmdlnopts.c:94 +#: cmdlnopts.c:100 msgid "set wheel position" msgstr " " -#: cmdlnopts.c:107 +#: cmdlnopts.c:113 msgid "shared memory (with image data) key (default: 7777777)" msgstr "" -#: cmdlnopts.c:50 +#: cmdlnopts.c:56 msgid "show this help" msgstr " " -#: cmdlnopts.c:109 +#: cmdlnopts.c:115 msgid "start (!=0) or stop(==0) infinity capturing loop" msgstr "" -#: cmdlnopts.c:52 +#: cmdlnopts.c:58 msgid "verbose level (-V - messages, -VV - debug, -VVV - all shit)" msgstr " (-V - , -VV - , -VVV - )" -#: cmdlnopts.c:71 +#: cmdlnopts.c:77 msgid "vertical binning to N pixels" msgstr " N " -#: cmdlnopts.c:67 +#: cmdlnopts.c:73 msgid "wait while exposition ends" msgstr ", " -#: cmdlnopts.c:45 +#: cmdlnopts.c:51 msgid "wheel device plugin (e.g. devdummy.so)" msgstr " (, devdummy.so)" diff --git a/server.c b/server.c index d7986db..51f426d 100644 --- a/server.c +++ b/server.c @@ -73,6 +73,7 @@ strpair allcommands[] = { { CC_CMD_FGOTO, "focuser position" }, { CC_CMD_FRAMEFORMAT, "camera frame format (X0,Y0,X1,Y1)" }, { CC_CMD_GAIN, "camera gain" }, + { CC_CMD_GETHEADERS, "get last file FITS headers" }, { CC_CMD_HBIN, "horizontal binning" }, { CC_CMD_HEADERFILES, "add FITS records from these files (comma-separated list)" }, { CC_CMD_HELP, "show this help" }, @@ -88,9 +89,10 @@ strpair allcommands[] = { { CC_CMD_OBJECT, "FITS 'OBJECT' field" }, { CC_CMD_OBJTYPE, "FITS 'IMAGETYP' field" }, { CC_CMD_OBSERVER, "FITS 'OBSERVER' field" }, + { CC_CMD_PLUGINCMD, "custom camera plugin command" }, { CC_CMD_PROGRAM, "FITS 'PROG-ID' field" }, { CC_CMD_RESTART, "restart server" }, - { CC_CMD_REWRITE, "rewrite file (if give `filename`, not `filenameprefix`" }, + { CC_CMD_REWRITE, "rewrite file (if give `filename`, not `filenameprefix`)" }, { CC_CMD_SHMEMKEY, "get shared memory key" }, { CC_CMD_SHUTTER, "camera shutter's operations" }, { CC_CMD_CAMTEMPER, "camera chip temperature" }, @@ -166,10 +168,9 @@ static inline void cameracapturestate(){ // capturing - wait for exposition ends camstate = CAMERA_ERROR; return; }else{ - /*if(lastfile){ (move calcstat into savefits) - TIMESTAMP("Calc stat"); - calculate_stat(ima); - }*/ + ima->gotstat = 0; // fresh image without statistics - recalculate when save + ima->timestamp = dtime(); // set timestamp + ++ima->imnumber; // increment counter if(saveFITS(ima, &lastfile)){ DBG("LAST file name changed"); } @@ -954,6 +955,24 @@ static cc_hresult inftyhandler(int fd, _U_ const char *key, const char *val){ return RESULT_SILENCE; } +// custom camera plugin command +static cc_hresult pluginhandler(int fd, _U_ const char *key, const char *val){ + if(!camera->plugincmd) return RESULT_BADKEY; + const char *r = camera->plugincmd(val); + if(!r) return RESULT_FAIL; + if(*r == 0) return RESULT_OK; + if(!cc_sendstrmessage(fd, r)) return RESULT_DISCONNECTED; + return RESULT_SILENCE; +} + +// get headers +static cc_hresult gethdrshandler(int fd, _U_ const char *key, _U_ const char *val){ + cc_charbuff *b = getFITSheader(ima); + if(!b) return RESULT_FAIL; + if(!cc_sendstrmessage(fd, b->buf)) return RESULT_DISCONNECTED; + return RESULT_SILENCE; +} + // for setters: do nothing when camera not in idle state static int CAMbusy(){ if(camera && camstate != CAMERA_IDLE){ @@ -1015,7 +1034,9 @@ static cc_handleritem items[] = { {chkcc, fastspdhandler, CC_CMD_FASTSPD}, {chkcc, darkhandler, CC_CMD_DARK}, {chkcc, inftyhandler, CC_CMD_INFTY}, + {chkcc, pluginhandler, CC_CMD_PLUGINCMD}, {NULL, tremainhandler, CC_CMD_TREMAIN}, + {chkcc, gethdrshandler, CC_CMD_GETHEADERS}, {NULL, FITSparhandler, CC_CMD_AUTHOR}, {NULL, FITSparhandler, CC_CMD_INSTRUMENT}, {NULL, FITSparhandler, CC_CMD_OBSERVER}, @@ -1034,6 +1055,7 @@ static cc_handleritem items[] = { }; #define CLBUFSZ BUFSIZ +#define STRBUFSZ (255) // send image as raw data static void sendimage(int client){ @@ -1072,11 +1094,10 @@ void server(int sock, int imsock){ } int nfd = 2; // only two listening sockets @start: command and image struct pollfd poll_set[CC_MAXCLIENTS+2]; - cc_charbuff *buffers[CC_MAXCLIENTS]; + cc_strbuff *buffers[CC_MAXCLIENTS]; for(int i = 0; i < CC_MAXCLIENTS; ++i){ - buffers[i] = cc_bufnew(CLBUFSZ); + buffers[i] = cc_strbufnew(CLBUFSZ, STRBUFSZ); } - char string[CLBUFSZ]; // string to read data from buffers bzero(poll_set, sizeof(poll_set)); // ZERO - listening server socket poll_set[0].fd = sock; @@ -1123,10 +1144,7 @@ void server(int sock, int imsock){ } // process some data & send messages to ALL if(camstate == CAMERA_FRAMERDY || camstate == CAMERA_ERROR){ - if(camstate == CAMERA_FRAMERDY){ - ima->timestamp = dtime(); // set timestamp - ++ima->imnumber; // increment counter - } + DBG("new image: timestamp=%.1f, num=%zd", ima->timestamp, ima->imnumber); char buff[PATH_MAX+32]; snprintf(buff, PATH_MAX, CC_CMD_EXPSTATE "=%d", camstate); DBG("Send %s to %d clients", buff, nfd - 2); @@ -1145,15 +1163,15 @@ void server(int sock, int imsock){ for(int fdidx = 2; fdidx < nfd; ++fdidx){ if((poll_set[fdidx].revents & POLLIN) == 0) continue; int fd = poll_set[fdidx].fd; - cc_charbuff *curbuff = buffers[fdidx-1]; + cc_strbuff *curbuff = buffers[fdidx-1]; int disconnected = 0; if(cc_read2buf(fd, curbuff)){ - size_t got = cc_getline(curbuff, string, CLBUFSZ); + size_t got = cc_getline(curbuff); if(got >= CLBUFSZ){ DBG("Client fd=%d gave buffer overflow", fd); LOGMSG("SERVER client fd=%d buffer overflow", fd); }else if(got){ - if(!parsestring(fd, items, string)) disconnected = 1; + if(!parsestring(fd, items, curbuff->string)) disconnected = 1; } }else disconnected = 1; if(disconnected){ @@ -1254,4 +1272,3 @@ static int parsestring(int fd, cc_handleritem *handlers, char *str){ DBG("Command not found!"); return cc_sendstrmessage(fd, cc_hresult2str(RESULT_BADKEY)); } -