mirror of
https://github.com/eddyem/CCD_Capture.git
synced 2026-03-20 08:40:56 +03:00
add some FITS header functions, change FITSsave, add plugin commands
This commit is contained in:
383
ccdcapture.c
383
ccdcapture.c
@@ -19,6 +19,7 @@
|
||||
#include <ctype.h> // isspace
|
||||
#include <dlfcn.h> // dlopen/close
|
||||
#include <fcntl.h>
|
||||
#include <float.h> // for float max
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user