diff --git a/CMakeLists.txt b/CMakeLists.txt index a6b9349..bc32c57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") if(NOT DEFINED LOCALEDIR) set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) endif() -set(SOURCES takepic.c usage.c camtools.c am.c macros.c) +set(SOURCES defhdrs.c takepic.c usage.c camtools.c am.c macros.c) if(NOT DEFINED NOBTA) set(SOURCES ${SOURCES} bta_print.c) add_definitions(-DUSE_BTA) @@ -28,6 +28,9 @@ endif() if(DEFINED TELLAT) add_definitions(-DTELLAT=${TELLAT}) endif() +if(DEFINED TELFOCUS) + add_definitions(-DTELFOCUS=${TELFOCUS}) +endif() if(NOT DEFINED PROCESSOR_COUNT) set(PROCESSOR_COUNT 2) # by default 2 cores set(cpuinfo_file "/proc/cpuinfo") diff --git a/README b/README index e0072e3..1f7d75a 100644 --- a/README +++ b/README @@ -3,7 +3,7 @@ This utilite depends on library libapogee & C-wrapper over it First, you should install a latest version of libapogee from directory "libapogee" or from original site: http://www.randomfactory.com/downloads/ If you will meet a bug in link stage ("can't find -lboost_regex-mt") cd to directory -libapogee-[version]/apogee and run +libapogee-[version]/apogee and run $ sed -i 's/boost_regex-mt/boost_regex/g' Makefile after this small fix cd .. and run make again. @@ -34,4 +34,14 @@ By default observatory location is SAO RAS, to change coordinates define: * -DTELLAT=lattitude in degr * -DTELLONG=longitude in degr * -DTELALT=altitude in m +* -DTELFOCUS=focal ratio of telescope in metres + + +user can store default headers in ~/apogee_hdrs.fits +user can give additional keys as command line parameters +to calculate simplest CDx_x coefficients user can give parameter ROT0: +- for left-handed system it shoud be less than 0 (-360..0) + CROTA2 = -ROT0 + PARANGLE - VAL_P +- for right-handed > 0 (0..360) + CROTA2 = ROT0 - PARANGLE + VAL_P diff --git a/TODO b/TODO new file mode 100644 index 0000000..bfd4a0d --- /dev/null +++ b/TODO @@ -0,0 +1,51 @@ + +Правильно писать шапку: +DATA - дата записи файла формата dd/mm/yy (UTC) +DATE-OBS - дата считывания данных с матрицы (начало, середина или конец - указывать в комментарии), dd/mm/yy, UTC +ORIGIN - место записи (SAO RAS, правильно) +INSTRUME - название прибора +CREATOR - название ПО, записавшего файл +EQUINOX - эпоха системы координат, используемой в файле (правильно) +EPOCH - Deprecated + +Комментарии, помимо COMMENT, могут просто начинаться с 9 столбца, оставляя первые 8 пустыми +Аналогично для HISTORY +(во всех трех случаях в столбце 9 не должно быть =) + + +Если данные непонятно в чем (особенно это касается таблиц), нужно использовать ключи: +BUNIT - binary unit (как для изображения, так и для таблиц) +TUNITn - единицы n-го столбца таблицы +см. http://www.lsw.uni-heidelberg.de/iau/units.html + +BITPIX: +8 - uint8_t +16 - int16_t (BZERO=32768 для uint16_t) +32 - int32_t (BZERO=2147483648 для uint32_t) +-32 - float +-64 - double + + +EXTEND = T +этот параметр не обязательно означает наличие "расширений", но если его нет, это гарантирует +отсутствие расширений + +Все расширения (изображения, таблицы и т.п.) должны начинаться со слова +XTENSION = [тип] - тип расширения (например, XTENSION= 'TABLE' +далее обязательны BITPIX, NAXIS и NAXIS1, NAXIS2 ... +Если данные отсутствуют, пишем NAXIS1 = 0 +Расширению можно дать имя (скажем, таблице): +EXTNAME = 'название' +их можно версионировать (EXTVER) и разделять по иерархии (EXTLEVEL) + + +ТАБЛИЦЫ: XTENSION='TABLE' +BITPIX=8 (ASCII) +NAXIS=2 (двумерная таблица) +NAXIS1= количество символов в строке таблицы (все столбцы) +NAXIS2= количество строк +PCOUNT=0 (ASCII) +GCOUNT=1 +TFIELDS= количество столбцов + + diff --git a/bta_print.c b/bta_print.c index 2569684..e56ae30 100644 --- a/bta_print.c +++ b/bta_print.c @@ -33,6 +33,8 @@ #include "camtools.h" #include "bta_print.h" #include "macros.h" +#include "usage.h" // command line parameters +#include "defhdrs.h" #include // SLA macros extern void sla_amp(double*, double*, double*, double*, double*, double*); @@ -51,7 +53,7 @@ void calc_mean(double appRA, double appDecl, double *r, double *d){ double ra, dec; appRA *= DS2R; appDecl *= DAS2R; - DBG("appRa: %g, appDecl: %g", appRA, appDecl); + //DBG("appRa: %g, appDecl: %g", appRA, appDecl); double mjd = JDate - jd0; slaamp(appRA, appDecl, mjd, 2000.0, &ra, &dec); ra *= DR2S; @@ -60,10 +62,9 @@ void calc_mean(double appRA, double appDecl, double *r, double *d){ if(d) *d = dec; } -#define CMNTSZ 79 -char comment[CMNTSZ + 1]; -#define CMNT(...) snprintf(comment, CMNTSZ, __VA_ARGS__) -#define FTKEY(...) WRITEKEY(fp, __VA_ARGS__, comment) +char comment[FLEN_CARD]; +#define CMNT(...) snprintf(comment, FLEN_CARD, __VA_ARGS__) +#define FTKEY(...) WRITEKEY(__VA_ARGS__, comment) #define WRITEHIST(fp) \ do{ if(test_headers){printf("HISTORY: %s\n", comment);}else{ \ int status = 0; \ @@ -140,6 +141,7 @@ BTA_Queue *bta_queue = NULL; void write_bta_data(fitsfile *fp){ char *val; double dtmp; + //char buf[FLEN_CARD]; time_t t_now = time(NULL); struct tm *tm_ut, *tm_loc; tm_ut = gmtime(&t_now); @@ -215,29 +217,33 @@ void write_bta_data(fitsfile *fp){ double a2000, d2000; calc_mean(InpAlpha, InpDelta, &a2000, &d2000); CMNT("R.A. given by user (for J2000): %s", time_asc(a2000)); - FTKEY(TDOUBLE, "INPRA0", &a2000); + dtmp = a2000 / 3600.; + FTKEY(TDOUBLE, "INPRA0", &dtmp); CMNT("Decl. given by user (for J2000): %s", angle_asc(d2000)); - FTKEY(TDOUBLE, "INPDEC0", &d2000); + dtmp = d2000 / 3600; + FTKEY(TDOUBLE, "INPDEC0", &dtmp); calc_mean(CurAlpha, CurDelta, &a2000, &d2000); CMNT("Current R.A. (for J2000): %s", time_asc(a2000)); - FTKEY(TDOUBLE, "CURRA0", &a2000); + dtmp = a2000 / 3600.; + FTKEY(TDOUBLE, "CURRA0", &dtmp); CMNT("Current Decl. (for J2000): %s", angle_asc(d2000)); - FTKEY(TDOUBLE, "CURDEC0", &d2000); + dtmp = d2000 / 3600; + FTKEY(TDOUBLE, "CURDEC0", &dtmp); // A / Azimuth CMNT("Current object Azimuth: %s", angle_asc(tag_A)); dtmp = tag_A / 3600.; FTKEY(TDOUBLE, "A", &dtmp); // Z / Zenith distance CMNT("Current object Zenith: %s", angle_asc(tag_Z)); dtmp = tag_Z / 3600.; FTKEY(TDOUBLE, "Z", &dtmp); - // ROTANGLE / Field rotation angle - CMNT("Field rotation angle: %s", angle_asc(tag_P)); - dtmp = tag_P / 3600.;FTKEY(TDOUBLE, "ROTANGLE", &dtmp); + // PARANGLE / Parallactic angle + CMNT("Parallactic angle: %s", angle_asc(tag_P)); + dtmp = tag_P / 3600.;FTKEY(TDOUBLE, "PARANGLE", &dtmp); CMNT("Telescope A: %s", angle_asc(val_A)); dtmp = val_A / 3600.; FTKEY(TDOUBLE, "VAL_A", &dtmp); CMNT("Telescope Z: %s", angle_asc(val_Z)); dtmp = val_Z / 3600.; FTKEY(TDOUBLE, "VAL_Z", &dtmp); - CMNT("Current P: %s", angle_asc(val_P)); + CMNT("Current P2 value: %s", angle_asc(val_P)); dtmp = val_P / 3600.; FTKEY(TDOUBLE, "VAL_P", &dtmp); CMNT("Dome A: %s", angle_asc(val_D)); diff --git a/camtools.c b/camtools.c index f86e562..b2dabf2 100644 --- a/camtools.c +++ b/camtools.c @@ -23,6 +23,7 @@ #include "camtools.h" #include "usage.h" #include "macros.h" +#include "defhdrs.h" #ifdef USE_BTA #include "bta_print.h" @@ -31,60 +32,6 @@ unsigned short max=0, min=65535; // extremums of current image double avr, std; // average value and standard deviation -/* - * Fake util to show FITS keys in stdout - * when test_headers == 1 - */ -void print_fits_header(fitsfile *fptr __attribute((unused)), int datatype, - char *keyname, void *value, char *comment){ - void _ub(char* r, void* p){snprintf(r, 80, "%hhu", *(unsigned char*)p);} - void _b(char* r, void* p){snprintf(r, 80, "%hhd", *(char*)p);} - void _us(char* r, void* p){snprintf(r, 80, "%hu", *(unsigned short*)p);} - void _ui(char* r, void* p){snprintf(r, 80, "%u", *(unsigned int*)p);} - void _ul(char* r, void* p){snprintf(r, 80, "%lu", *(unsigned long*)p);} - void _s(char* r, void* p){snprintf(r, 80, "%hd", *(short*)p);} - void _i(char* r, void* p){snprintf(r, 80, "%d", *(int*)p);} - void _l(char* r, void* p){snprintf(r, 80, "%ld", *(long*)p);} - void _ll(char* r, void* p){snprintf(r, 80, "%lld", *(long long*)p);} - void _f(char* r, void* p){snprintf(r, 80, "%g", *(float*)p);} - void _d(char* r, void* p){snprintf(r, 80, "%g", *(double*)p);} - void _fc(char* r, void* p){snprintf(r, 80, "(%.8g, %.8g)", - ((float*)p)[0], ((float*)p)[1]);} - void _dc(char* r, void* p){snprintf(r, 80, "(%.8g, %.8g)", - ((double*)p)[0], ((double*)p)[1]);} - void _log(char* r, void* p){snprintf(r, 80, "'%s'", (int*)p ? "true" : "false");} - void _str(char* r, void* p){snprintf(r, 80, "'%s'", (char*)p);} - void _unk(char* r, void* p __attribute((unused))){sprintf(r, "unknown datatype");} - char tmp[81], res[81]; - void (*__)(char*, void*); - switch(datatype){ - case TBIT: - case TBYTE: __ = _ub; break; - case TSBYTE: __ = _b; break; - case TUSHORT: __ = _us; break; - case TUINT: __ = _ui; break; - case TULONG: __ = _ul; break; - case TSHORT: __ = _s; break; - case TINT: __ = _i; break; - case TLONG: __ = _l; break; - case TLONGLONG: __ = _ll; break; - case TFLOAT: __ = _f; break; - case TDOUBLE: __ = _d; break; - case TCOMPLEX: __ = _fc; break; - case TDBLCOMPLEX: __ = _dc; break; - case TLOGICAL: __ = _log; break; - case TSTRING: __ = _str; break; - default: __ = _unk; - } - __(res, value); - if(strlen(res) < 20) - snprintf(tmp, 80, "%-8s = %-20s", keyname, res); - else - snprintf(tmp, 80, "%-8s = %s", keyname, res); - snprintf(res, 80, "%s / %s", tmp, comment); - printf("%s\n", res); -} - /* * set fun speed * if user set option fan-speed=F, then speed would be set to F @@ -225,63 +172,60 @@ int writefits(char *filename, int width, int height, void *data){ TRYFITS(fits_create_file, &fp, filename); TRYFITS(fits_create_img, fp, USHORT_IMG, 2, naxes); // FILE / Input file original name - WRITEKEY(fp, TSTRING, "FILE", filename, "Input file original name"); + WRITEKEY(TSTRING, "FILE", filename, "Input file original name"); /* * Detector parameters */ // DETECTOR / detector if(camera){ - WRITEKEY(fp, TSTRING, "DETECTOR", camera, "Detector model"); + WRITEKEY(TSTRING, "DETECTOR", camera, "Detector model"); } // SENSOR / sensor if(sensor){ - WRITEKEY(fp, TSTRING, "SENSOR", sensor, "Camera sensor model"); + WRITEKEY(TSTRING, "SENSOR", sensor, "Camera sensor model"); } // INSTRUME / Instrument if(instrument){ - WRITEKEY(fp, TSTRING, "INSTRUME", instrument, "Instrument"); + WRITEKEY(TSTRING, "INSTRUME", instrument, "Instrument"); }else - WRITEKEY(fp, TSTRING, "INSTRUME", "direct imaging", "Instrument"); + WRITEKEY(TSTRING, "INSTRUME", "direct imaging", "Instrument"); snprintf(buf, 79, "%.g x %.g", pixX, pixY); // PXSIZE / pixel size - WRITEKEY(fp, TSTRING, "PXSIZE", buf, "Pixel size in mkm"); + WRITEKEY(TSTRING, "PXSIZE", buf, "Pixel size in mkm"); // XPIXELSZ, YPIXELSZ -- the same - WRITEKEY(fp, TDOUBLE, "XPIXELSZ", &pixX, "X pixel size in mkm"); - WRITEKEY(fp, TDOUBLE, "YPIXELSZ", &pixY, "Y pixel size in mkm"); - WRITEKEY(fp, TSTRING, "VIEW_FIELD", viewfield, "Camera field of view"); - // CRVAL1, CRVAL2 / Offset in X, Y - if(X0) WRITEKEY(fp, TINT, "CRVAL1", &X0, "Offset in X"); - if(Y0) WRITEKEY(fp, TINT, "CRVAL2", &Y0, "Offset in Y"); + WRITEKEY(TDOUBLE, "XPIXELSZ", &pixX, "X pixel size in mkm"); + WRITEKEY(TDOUBLE, "YPIXELSZ", &pixY, "Y pixel size in mkm"); + WRITEKEY(TSTRING, "VIEWFLD", viewfield, "Camera field of view"); if(exptime == 0) sprintf(buf, "bias"); else if(shutter == 0) sprintf(buf, "dark"); else if(objtype) strncpy(buf, objtype, 79); else sprintf(buf, "object"); // IMAGETYP / object, flat, dark, bias, scan, eta, neon, push - WRITEKEY(fp, TSTRING, "IMAGETYP", buf, "Image type"); + WRITEKEY(TSTRING, "IMAGETYP", buf, "Image type"); // DATAMAX, DATAMIN / Max,min pixel value ustmp = ((twelveBit) ? 4095 : 65535); - WRITEKEY(fp, TUSHORT, "DATAMAX", &ustmp, "Max pixel value"); + WRITEKEY(TUSHORT, "DATAMAX", &ustmp, "Max pixel value"); ustmp = 0; - WRITEKEY(fp, TUSHORT, "DATAMIN", &ustmp, "Min pixel value"); + WRITEKEY(TUSHORT, "DATAMIN", &ustmp, "Min pixel value"); // Some Statistics - WRITEKEY(fp, TUSHORT, "STATMAX", &max, "Max data value"); - WRITEKEY(fp, TUSHORT, "STATMIN", &min, "Min data value"); - WRITEKEY(fp, TDOUBLE, "STATAVR", &avr, "Average data value"); - WRITEKEY(fp, TDOUBLE, "STATSTD", &std, "Standart deviation of data value"); + WRITEKEY(TUSHORT, "STATMAX", &max, "Max data value"); + WRITEKEY(TUSHORT, "STATMIN", &min, "Min data value"); + WRITEKEY(TDOUBLE, "STATAVR", &avr, "Average data value"); + WRITEKEY(TDOUBLE, "STATSTD", &std, "Standart deviation of data value"); // Temperatures - WRITEKEY(fp, TDOUBLE, "TEMP0", &temperature, "Camera temperature at exp. start (degr C)"); - WRITEKEY(fp, TDOUBLE, "TEMP1", &t_int, "Camera temperature at exp. end (degr C)"); + WRITEKEY(TDOUBLE, "TEMP0", &temperature, "Camera temperature at exp. start (degr C)"); + WRITEKEY(TDOUBLE, "TEMP1", &t_int, "Camera temperature at exp. end (degr C)"); if(t_ext > -30.) // there's a hot temp sensor - WRITEKEY(fp, TDOUBLE, "TEMPBODY", &t_ext, "Camera body temperature at exp. end (degr C)"); + WRITEKEY(TDOUBLE, "TEMPBODY", &t_ext, "Camera body temperature at exp. end (degr C)"); tmp = (temperature + t_int) / 2. + 273.15; // CAMTEMP / Camera temperature (K) - WRITEKEY(fp, TDOUBLE, "CAMTEMP", &tmp, "Camera temperature (K)"); + WRITEKEY(TDOUBLE, "CAMTEMP", &tmp, "Camera temperature (K)"); tmp = (double)exptime / 1000.; // EXPTIME / actual exposition time (sec) - WRITEKEY(fp, TDOUBLE, "EXPTIME", &tmp, "actual exposition time (sec)"); + WRITEKEY(TDOUBLE, "EXPTIME", &tmp, "actual exposition time (sec)"); // DATE / Creation date (YYYY-MM-DDThh:mm:ss, UTC) strftime(buf, 79, "%Y-%m-%dT%H:%M:%S", gmtime(&savetime)); - WRITEKEY(fp, TSTRING, "DATE", buf, "Creation date (YYYY-MM-DDThh:mm:ss, UTC)"); + WRITEKEY(TSTRING, "DATE", buf, "Creation date (YYYY-MM-DDThh:mm:ss, UTC)"); tm_starttime = localtime(&expStartsAt); /* * startTime = (long)expStartsAt; @@ -290,7 +234,7 @@ int writefits(char *filename, int width, int height, void *data){ */ strftime(buf, 79, "%Y-%m-%dT%H:%M:%S", tm_starttime); // DATE-OBS / DATE OF OBS. - WRITEKEY(fp, TSTRING, "DATE-OBS", buf, "DATE OF OBS. (YYYY-MM-DDThh:mm:ss, local)"); + WRITEKEY(TSTRING, "DATE-OBS", buf, "DATE OF OBS. (YYYY-MM-DDThh:mm:ss, local)"); /* * // START / Measurement start time (local) (hh:mm:ss) * strftime(buf, 79, "%H:%M:%S", tm_starttime); @@ -298,30 +242,32 @@ int writefits(char *filename, int width, int height, void *data){ */ // OBJECT / Object name if(objname){ - WRITEKEY(fp, TSTRING, "OBJECT", objname, "Object name"); + WRITEKEY(TSTRING, "OBJECT", objname, "Object name"); } // BINNING / Binning if(hbin != 1 || vbin != 1){ snprintf(buf, 79, "%d x %d", hbin, vbin); - WRITEKEY(fp, TSTRING, "BINNING", buf, "Binning (hbin x vbin)"); + WRITEKEY(TSTRING, "BINNING", buf, "Binning (hbin x vbin)"); } - WRITEKEY(fp, TINT, "XBIN", &hbin, "Horizontal binning"); - WRITEKEY(fp, TINT, "YBIN", &vbin, "Vertical binning"); + WRITEKEY(TINT, "XBIN", &hbin, "Horizontal binning"); + WRITEKEY(TINT, "YBIN", &vbin, "Vertical binning"); // OBSERVER / Observers if(observers){ - WRITEKEY(fp, TSTRING, "OBSERVER", observers, "Observers"); + WRITEKEY(TSTRING, "OBSERVER", observers, "Observers"); } // PROG-ID / Observation program identifier if(prog_id){ - WRITEKEY(fp, TSTRING, "PROG-ID", prog_id, "Observation program identifier"); + WRITEKEY(TSTRING, "PROG-ID", prog_id, "Observation program identifier"); } // AUTHOR / Author of the program if(author){ - WRITEKEY(fp, TSTRING, "AUTHOR", author, "Author of the program"); + WRITEKEY(TSTRING, "AUTHOR", author, "Author of the program"); } #ifdef USE_BTA write_bta_data(fp); #endif + check_wcs(); + write_list(fp); TRYFITS(fits_write_img, fp, TUSHORT, 1, width * height, data); TRYFITS(fits_close_file, fp); return 0; diff --git a/camtools.h b/camtools.h index 412e685..b11ec9a 100644 --- a/camtools.h +++ b/camtools.h @@ -30,13 +30,7 @@ do{if(!test_headers){ int status = 0; \ fits_report_error(stderr, status); \ return -1;} \ }}while(0) -#define WRITEKEY(...) \ -do{ if(test_headers){ \ - print_fits_header(__VA_ARGS__); \ - }else{ int status = 0; \ - fits_write_key(__VA_ARGS__, &status); \ - if(status) fits_report_error(stderr, status);\ -}}while(0) +#define WRITEKEY(...) do{add_fits_header(__VA_ARGS__);}while(0) void print_fits_header(fitsfile *fptr, int datatype, char *keyname, void *value, char *comment); diff --git a/defhdrs.c b/defhdrs.c new file mode 100644 index 0000000..4401a52 --- /dev/null +++ b/defhdrs.c @@ -0,0 +1,435 @@ +/* + * defhdrs.c - read default headers from user file + * + * Copyright 2016 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +/* + * Only these parameters are recognized: +SUBNET (instead of -E) +CAMMSGID (instead of -M) +INSTRUME +OBSERVER +PROG-ID +AUTHOR + +XPIXELSZ +YPIXELSZ +IMSCALE + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + + +#include "defhdrs.h" +#include "usage.h" +#include "macros.h" +#include "camtools.h" + +// global keylist +static KeyList *FITS_keys = NULL; +double crval1 = -5e5, crval2 = -5e5, crpix1 = -5e5, crpix2 = -5e5; +double CD[2][2] = {{0.,0.}, {0.,0.}}; + +void get_defhdrs(char *fname){ + mmapbuf *mmb = NULL; + if(!fname){ // find in default file: ~/$DEFCONF + const char *homedir; + if ((homedir = getenv("HOME")) == NULL){ + homedir = getpwuid(getuid())->pw_dir; + } + size_t L = strlen(homedir) + strlen(DEFCONF) + 2; + fname = malloc(L); + snprintf(fname, L, "%s/%s", homedir, DEFCONF); + mmb = My_mmap(fname); + FREE(fname); + }else mmb = My_mmap(fname); + if(!mmb) return; + char *hdrs = strdup(mmb->data); + My_munmap(mmb); + char *nl = NULL; + while((nl = strchr(hdrs, '\n'))){ + *nl = 0; + list_add_record(&FITS_keys, hdrs, 1); + hdrs = nl + 1; + } + if(*hdrs){ // last line in file didn't have newline + list_add_record(&FITS_keys, hdrs, 1); + } +} + +/** + * Add headers from command line parameters + * something like `apogee_control filename "KEY1 = VAL1 / comment" "KEYn = VALn / comment" + */ +void add_morehdrs(int argc, char **argv){ + int i; + char buf[FLEN_CARD]; + for(i = 0; i < argc; ++i){ // we should override parameters from default configuration file + char *dup = strdup(argv[i]); + char *eq = strchr(dup, '='); + if(eq){ + *(eq++) = 0; + KeyList *found = list_find_key(FITS_keys, dup); + if(found) list_modify_key(FITS_keys, dup, eq, 2); // comments (if exists in new header) will be override too + else{ + snprintf(buf, FLEN_CARD, "%-8s= %s", dup, eq); + list_add_record(&FITS_keys, buf, 2); + } + }else{ // comment or something else + list_add_record(&FITS_keys, dup, 2); + } + FREE(dup); + } +} + +KeyList *list_get_end(KeyList *list){ + if(!list) return NULL; + KeyList *first = list; + if(list->last) return list->last; + while(list->next) list = list->next; + first->last = list; + return list; +} + +/** + * add record to keylist + * @param list (io) - pointer to root of list or NULL + * if *root == NULL, just created node will be placed there + * @param rec - data inserted + * @return pointer to created node + */ +KeyList *list_add_record(KeyList **list, char *rec, int immutable){ + KeyList *node, *last; + if((node = (KeyList*) MALLOC(KeyList, 1)) == 0) return NULL; // allocation error + node->record = strdup(rec); // insert data + node->immutable = immutable; + DBG("add record %s", rec); + if(!node->record){ + /// "п²п╣ п╪п╬пЁя┐ я│п╨п╬п©п╦я─п╬п╡п╟я┌я▄ п╢п╟п╫п╫я▀п╣" + WARNX(_("Can't copy data")); + return NULL; + } + if(list){ + if(*list){ // there was root node - search last + last = list_get_end(*list); + last->next = node; // insert pointer to new node into last element in list + (*list)->last = node; + // DBG("last node %s", (*list)->last->record); + }else *list = node; + } + return node; +} + +// compare keywords from `list` and `keyname` +int compare_keyw(KeyList *list, char *keyname){ + if(!list || !keyname || !list->record) return 0; + size_t L = strlen(keyname); + if(strncmp(list->record, keyname, L) == 0){ // key found + char *ltr = list->record + L; + while(*ltr == ' ') ++ltr; // omit spaces + if(*ltr == '=') return 1; // only if there's equal sign after keyname! + } + return 0; +} + +/** + * return record with given key or NULL + */ +KeyList *list_find_key(KeyList *list, char *keyname){ + if(!list || !keyname) return NULL; + do{ + if(compare_keyw(list, keyname)) return list; + list = list->next; + }while(list); + return NULL; +} + +/** + * find value of key + * @return NULL if not found or strdup`ed value + */ +char *list_find_keyval(KeyList *l, char *key){ + KeyList *list = list_find_key(l, key); + if(!list) return NULL; + char *rec = strdup(list->record); + char *val = strchr(rec, '='); + *val++ = 0; + char *com = strchr(val, '/'); + if(com) *com = 0; + char *retval = strdup(val); + FREE(rec); + return retval; +} + +int getdoubleval(double *val, KeyList *list, char *key){ + char *v = list_find_keyval(list, key); + if(!v) return 0; + *val = strtod(v, NULL); + FREE(v); + return 1; +} + +/** + * modify key value + * return NULL if given key is absent + */ +KeyList *list_modify_key(KeyList *list, char *key, char *newval, int immutable){ + char buf[FLEN_CARD]; + KeyList *rec = list_find_key(list, key); + if(!rec) return NULL; + if(rec->immutable > immutable) return NULL; // not modify immutable records + rec->immutable = immutable; + newval = strdup(newval); + char *comnt = strchr(newval, '/'); + if(comnt){ + *(comnt++) = 0; + }else{ + comnt = strchr(rec->record, '/'); + if(comnt) ++comnt; + } + if(comnt){ + snprintf(buf, FLEN_CARD, "%-8s= %-21s/%s", key, newval, comnt); + }else{ + snprintf(buf, FLEN_CARD, "%-8s= %s", key, newval); + } + FREE(rec->record); + FREE(newval); + DBG("modify record %s", buf); + rec->record = strdup(buf); + return rec; +} + +void add_fits_header(int datatype, char *keyname, void *value, char *comment){ + void _ub(char* r, void* p){snprintf(r, FLEN_CARD, "%20hhu", *(unsigned char*)p);} + void _b(char* r, void* p){snprintf(r, FLEN_CARD, "%20hhd", *(char*)p);} + void _us(char* r, void* p){snprintf(r, FLEN_CARD, "%20hu", *(unsigned short*)p);} + void _ui(char* r, void* p){snprintf(r, FLEN_CARD, "%20u", *(unsigned int*)p);} + void _ul(char* r, void* p){snprintf(r, FLEN_CARD, "%20lu", *(unsigned long*)p);} + void _s(char* r, void* p){snprintf(r, FLEN_CARD, "%20hd", *(short*)p);} + void _i(char* r, void* p){snprintf(r, FLEN_CARD, "%20d", *(int*)p);} + void _l(char* r, void* p){snprintf(r, FLEN_CARD, "%20ld", *(long*)p);} + void _ll(char* r, void* p){snprintf(r, FLEN_CARD, "%20lld", *(long long*)p);} + void _f(char* r, void* p){snprintf(r, FLEN_CARD, "%20.8f", *(float*)p);} + void _d(char* r, void* p){snprintf(r, FLEN_CARD, "%20.8f", *(double*)p);} + void _fc(char* r, void* p){snprintf(r, FLEN_CARD, "(%.8f, %.8f)", + ((float*)p)[0], ((float*)p)[1]);} + void _dc(char* r, void* p){snprintf(r, FLEN_CARD, "(%.8f, %.8f)", + ((double*)p)[0], ((double*)p)[1]);} + void _log(char* r, void* p){snprintf(r, FLEN_CARD, "'%s'", (int*)p ? "true" : "false");} + void _str(char* r, void* p){snprintf(r, FLEN_CARD, "'%s'", (char*)p);} + void _unk(char* r, void* p __attribute((unused))){sprintf(r, "unknown datatype");} + char tmp[FLEN_CARD], res[FLEN_CARD]; + void (*__)(char*, void*); + switch(datatype){ + case TBIT: + case TBYTE: __ = _ub; break; + case TSBYTE: __ = _b; break; + case TUSHORT: __ = _us; break; + case TUINT: __ = _ui; break; + case TULONG: __ = _ul; break; + case TSHORT: __ = _s; break; + case TINT: __ = _i; break; + case TLONG: __ = _l; break; + case TLONGLONG: __ = _ll; break; + case TFLOAT: __ = _f; break; + case TDOUBLE: __ = _d; break; + case TCOMPLEX: __ = _fc; break; + case TDBLCOMPLEX: __ = _dc; break; + case TLOGICAL: __ = _log; break; + case TSTRING: __ = _str; break; + default: __ = _unk; + } + __(res, value); + KeyList *rec = list_find_key(FITS_keys, keyname); + if(rec){ + if(comment){ + if(strlen(res) < 21) + snprintf(tmp, FLEN_CARD, "%-21s / %s", res, comment); + else + snprintf(tmp, FLEN_CARD, "%s / %s", res, comment); + }else snprintf(tmp, FLEN_CARD, "%s", res); + list_modify_key(FITS_keys, keyname, tmp, 0); + }else{ + if(strlen(res) < 21) + snprintf(tmp, FLEN_CARD, "%-8s= %-20s", keyname, res); + else + snprintf(tmp, FLEN_CARD, "%-8s=%s", keyname, res); + snprintf(res, FLEN_CARD, "%s / %s", tmp, comment); + list_add_record(&FITS_keys, res, 0); + } +} + +/** + * free list memory & set it to NULL + */ +void list_free(KeyList **list){ + KeyList *node = *list, *next; + if(!list || !*list) return; + do{ + next = node->next; + FREE(node->record); + free(node); + node = next; + }while(node); + *list = NULL; +} + +void free_fits_list(){ list_free(&FITS_keys); } +/* +void list_print(KeyList *list){ + while(list){ + printf("%s\n", list->record); + list = list->next; + } +} +void show_list(){ + list_print(FITS_keys); +} +*/ + +void write_list(fitsfile *fp){ + if(FITS_keys){ // there's keys + KeyList *records = FITS_keys; + while(records){ + char *rec = records->record; + records = records->next; + if(strncmp(rec, "SIMPLE", 6) == 0 || strncmp(rec, "EXTEND", 6) == 0) // key "file does conform ..." + continue; + // comment of obligatory key in FITS head + else if(strncmp(rec, "COMMENT FITS", 14) == 0 || strncmp(rec, "COMMENT and Astrophysics", 26) == 0) + continue; + else if(strncmp(rec, "NAXIS", 5) == 0 || strncmp(rec, "BITPIX", 6) == 0) // NAXIS, NAXISxxx, BITPIX + continue; + if(!test_headers){ + int status = 0; + fits_write_record(fp, rec, &status); + if(status) fits_report_error(stderr, status); + }else + printf("%s\n", rec); + } + } +} + +/** + * Check if user tell some information about WCS and add it into headers + */ +void check_wcs(){ + double cd = -5e5, crot = -5e5, rot0 = -5e5; + char buf[FLEN_CARD]; + // first correct scale: user value SCALE will fix parameter imscale + if(imscale < 0.) getdoubleval(&imscale, FITS_keys, "SCALE"); + if(imscale < 0.){ + imscale = 180.*3600./M_PI / TELFOCUS / 1000000. * sqrt(pixX*pixY); // default system value + } + snprintf(buf, FLEN_CARD, "%.4f x %.4f", imscale * hbin, imscale * vbin); + WRITEKEY(TSTRING, "IMSCALE", buf, "image scale (''/Pix x ''/Pix)"); + + int cnt = getdoubleval(&crval1, FITS_keys, "CRVAL1"); + cnt += getdoubleval(&crval2, FITS_keys, "CRVAL1"); + cnt += getdoubleval(&crpix1, FITS_keys, "CRPIX1"); + cnt += getdoubleval(&crpix2, FITS_keys, "CRPIX2"); + cnt += getdoubleval(&cd, FITS_keys, "CD1_1"); + cnt += getdoubleval(&crot, FITS_keys, "CROTA2"); + cnt += getdoubleval(&rot0, FITS_keys, "ROT0"); + DBG("cnt = %d", cnt); + if(!cnt) return; + int wcs = 2; + WRITEKEY(TINT, "WCSAXIS", &wcs, "Number of WCS axes"); + WRITEKEY(TSTRING, "CTYPE1", "RA---TAN", "RA-Gnomic projection"); + WRITEKEY(TSTRING, "CUNIT1", "deg", "RA units - degrees"); + WRITEKEY(TSTRING, "CTYPE2", "DEC---TAN", "Decl-Gnomic projection"); + WRITEKEY(TSTRING, "CUNIT2", "deg", "Decl units - degrees"); + // CRVAL1 = / RA of reference pixel + if(crval1 > -4e-5) + WRITEKEY(TDOUBLE, "CRVAL1", &crval1, "RA of reference pixel"); + else crval1 = 0; + // CRVAL2 = / Decl of reference pixel + if(crval2 > -4e-5) + WRITEKEY(TDOUBLE, "CRVAL2", &crval2, "Decl of reference pixel"); + else crval2 = 0; + //CRPIX1 = / X reference pixel + if(crpix1 > -4e-5) + WRITEKEY(TDOUBLE, "CRPIX1", &crpix1, "X reference pixel"); + else crpix1 = 0; + //CRPIX2 = / Y reference pixel + if(crpix2 > -4e-5) + WRITEKEY(TDOUBLE, "CRPIX2", &crpix2, "Y reference pixel"); + else crpix2 = 0; + cnt = 0; + if(cd > -4e5){ + ++cnt; + WRITEKEY(TDOUBLE, "CD1_1", &cd, "rotation matrix coefficient [1,1]"); + CD[0][0] = cd; + } + if(getdoubleval(&cd, FITS_keys, "CD1_2")){ + ++cnt; + WRITEKEY(TDOUBLE, "CD1_2", &cd, "rotation matrix coefficient [1,2]"); + CD[0][1] = cd; + } + if(getdoubleval(&cd, FITS_keys, "CD2_1")){ + ++cnt; + WRITEKEY(TDOUBLE, "CD2_1", &cd, "rotation matrix coefficient [2,1]"); + CD[1][0] = cd; + } + if(getdoubleval(&cd, FITS_keys, "CD2_2")){ + ++cnt; + WRITEKEY(TDOUBLE, "CD2_2", &cd, "rotation matrix coefficient [2,2]"); + CD[1][1] = cd; + } + if(cnt == 4) return; + // no coefficients - use CROTA & CDELT + cnt = 0; + if(crot > -4e5){ + ++cnt; + DBG("crot: %g", crot); + WRITEKEY(TDOUBLE, "CROTA2", &crot, "North rotation angle"); + } + if(getdoubleval(&crot, FITS_keys, "CDELT1")){ + ++cnt; + WRITEKEY(TDOUBLE, "CDELT1", &crot, "X axis scale"); + getdoubleval(&crot, FITS_keys, "CDELT2"); + WRITEKEY(TDOUBLE, "CDELT2", &crot, "Y axis scale"); // use CDELT1 if user omits CDELT2 + } + if(cnt == 2) return; + // still no coefficients - try to calculate CDx_x by user data + double parangle, rotangle; + if(rot0 < -4e5) return; // no values + if(!getdoubleval(¶ngle, FITS_keys, "PARANGLE")) return; + if(!getdoubleval(&rotangle, FITS_keys, "VAL_P")) return; + double s, c, scx = imscale / 3600. * hbin, scy = imscale / 3600. * vbin; + if(rot0 < 0){ // left-handed + crot = (-rot0 + parangle - rotangle)*M_PI/180; + DBG("crot = %g", crot*180/M_PI); + sincos(crot, &s, &c); + CD[0][0] = -scx * c; CD[0][1] = scy * s; + CD[1][0] = scx * s; CD[1][1] = scy * c; + }else{ // right-handed + crot = (rot0 - parangle + rotangle)*M_PI/180; + sincos(crot, &s, &c); + CD[0][0] = scx * c; CD[0][1] = -scy * s; + CD[1][0] = scx * s; CD[1][1] = scy * c; + } + WRITEKEY(TDOUBLE, "CD1_1", &CD[0][0], "rotation matrix coefficient [1,1]"); + WRITEKEY(TDOUBLE, "CD1_2", &CD[0][1], "rotation matrix coefficient [1,2]"); + WRITEKEY(TDOUBLE, "CD2_1", &CD[1][0], "rotation matrix coefficient [2,1]"); + WRITEKEY(TDOUBLE, "CD2_2", &CD[1][1], "rotation matrix coefficient [2,2]"); +} diff --git a/defhdrs.h b/defhdrs.h new file mode 100644 index 0000000..06fd91b --- /dev/null +++ b/defhdrs.h @@ -0,0 +1,52 @@ +/* + * defhdrs.h + * + * Copyright 2016 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __DEFHDRS_H__ +#define __DEFHDRS_H__ + +extern double crval1, crval2, crpix1, crpix2, CD[2][2]; // global coefficients for WCS + +typedef struct klist_{ + char *record; + int immutable; // not modify record if old value of `immutable` > new value + struct klist_ *next; + struct klist_ *last; +} KeyList; + +void list_free(KeyList **list); +void free_fits_list(); +KeyList *list_add_record(KeyList **list, char *rec, int immutable); +KeyList *list_find_key(KeyList *list, char *key); +KeyList *list_modify_key(KeyList *list, char *key, char *newval, int immutable); +KeyList *list_get_end(KeyList *list); +/* +void list_print(KeyList *list); +void show_list(); +*/ +void add_fits_header(int datatype, char *keyname, void *value, char *comment); + +void write_list(fitsfile *fp); +void get_defhdrs(char *fname); +void add_morehdrs(int argc, char **argv); + +void check_wcs(); + +#endif // __DEFHDRS_H__ diff --git a/macros.c b/macros.c index cc6bfe1..36ac09c 100644 --- a/macros.c +++ b/macros.c @@ -172,15 +172,16 @@ mmapbuf *My_mmap(char *filename){ char *ptr; size_t Mlen; struct stat statbuf; - if(!filename) ERRX(_("No filename given!")); + DBG("Try to mmap %s", filename); + if(!filename) return NULL; if((fd = open(filename, O_RDONLY)) < 0) - ERR(_("Can't open %s for reading"), filename); + return NULL; if(fstat (fd, &statbuf) < 0) - ERR(_("Can't stat %s"), filename); + return NULL; Mlen = statbuf.st_size; if((ptr = mmap (0, Mlen, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) - ERR(_("Mmap error for input")); - if(close(fd)) ERR(_("Can't close mmap'ed file")); + return NULL; + if(close(fd)) return NULL; mmapbuf *ret = MALLOC(mmapbuf, 1); ret->data = ptr; ret->len = Mlen; @@ -189,7 +190,7 @@ mmapbuf *My_mmap(char *filename){ void My_munmap(mmapbuf *b){ if(munmap(b->data, b->len)) - ERR(_("Can't munmap")); + WARN(_("Can't munmap")); FREE(b); } diff --git a/takepic.c b/takepic.c index 085c77a..dbbe279 100644 --- a/takepic.c +++ b/takepic.c @@ -29,6 +29,7 @@ #include #include +#include "defhdrs.h" #include "usage.h" #include "camtools.h" #ifdef USE_BTA @@ -44,7 +45,7 @@ #define TMBUFSIZ 40 // time string buffer length -char *pidfilename = "/tmp/takepic.pid"; // pidfile +char *pidfilename = "/tmp/apogee_control.pid"; // pidfile char tm_buf[TMBUFSIZ]; // time string buffer @@ -692,6 +693,7 @@ returning: restore_signals(); DBG("free buffers & close files"); free(buf); + free_fits_list(); if(f_tlog) fclose(f_tlog); if(f_statlog) fclose(f_statlog); #ifdef IMAGEVIEW diff --git a/takepic.h b/takepic.h index eb02b11..646afc4 100644 --- a/takepic.h +++ b/takepic.h @@ -21,7 +21,9 @@ #pragma once #ifndef __TAKEPIC_H__ #define __TAKEPIC_H__ +#ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 501 +#endif #include #include #include @@ -56,40 +58,24 @@ * SAO longitude 41 26 29.175 * SAO latitude 43 39 12.7 * SAO altitude 2070 + * BTA focal ratio 24.024 m */ #ifndef TELLAT - #define TELLAT 43.6535278 + #define TELLAT (43.6535278) #endif #ifndef TELLONG - #define TELLONG 41.44143375 + #define TELLONG (41.44143375) #endif #ifndef TELALT - #define TELALT 2070.0 + #define TELALT (2070.0) +#endif +#ifndef TELFOCUS + #define TELFOCUS (24.024) +#endif +// filename for default headers (in ~) +#ifndef DEFCONF +#define DEFCONF "apogee_hdrs.fits" #endif - -/* -#define _(String) gettext(String) -#define gettext_noop(String) String -#define N_(String) gettext_noop(String) -// режим отладки, -DEBUG -#ifdef EBUG - #define RED "\033[1;32;41m" - #define GREEN "\033[5;30;42m" - #define OLDCOLOR "\033[0;0;0m" - #define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__) - #define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n");} while(0) - #define ERR(...) DBG(__VA_ARGS__) -#else - #define FNAME() do{}while(0) - #define DBG(...) do{}while(0) - #define ERR(...) do{fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n");} while(0) -#endif //EBUG - -*/ - extern int test_headers; extern const char *__progname; @@ -98,14 +84,4 @@ extern const char *__progname; printf(format, ## args); \ printf("\n");}while(0) -/* -#define warnc(c, format, args...) \ - warnx(format ": %s", ## args, strerror(c)) -long r; -#define TRYFUNC(f, ...) \ -do{ if((r = f(__VA_ARGS__))) \ - warnc(-r, #f "() failed"); \ -}while(0) -*/ - #endif // __TAKEPIC_H__ diff --git a/usage.c b/usage.c index 8ca5f69..c7f370c 100644 --- a/usage.c +++ b/usage.c @@ -21,6 +21,7 @@ #include "usage.h" #include "macros.h" +#include "defhdrs.h" Apn_Filter Tturret = Apn_Filter_FW50_7S; // turrer type int @@ -43,6 +44,7 @@ char ,*author = NULL // author of program ,*subnet = NULL // subnet for ethernet camera discovery ,*cammsgid = NULL // MSG-ID of camera + ,*defhdr_filename = NULL // name of file with default headers ; int exptime = -1 // exposition time (in ms), -1 means no exposition @@ -65,7 +67,11 @@ int ,flipY = 0 // flip image around Y axe (horizontal flip) ,histry = 0 // write history at expositions ; -double temperature = -25.; // setpoint of temperature +double + temperature = -25. // setpoint of temperature + ,imscale = -1. // image scale (''/pix) given by user +; + int shutter = 1; // object frame == 1, dark frame == 0 @@ -125,31 +131,37 @@ void usage(char *fmt, ...){ } va_end(ap); // "Использование:\t%s [опции] [префикс выходных файлов]\n" - printf(_("Usage:\t%s [options] [output files prefix]\n"), + printf(_("Usage:\t%s [options] [output files prefix] [additional headers]\n"), __progname); // "\tОпции:\n" printf(_("\tOptions:\n")); printf("\t-A,\t--author=author\t\t%s\n", // "автор программы" _("program author")); + printf("\t-b,\t--defhdr=filename\t%s\n", + // "имя файла с заголовками по умолчанию" + _("file with default headers")); printf("\t-c,\t--cooler-off\t\t%s\n", // "отключить холодильник" - _("Set cooler off")); + _("set cooler off")); + printf("\t-C,\t--imscale\t\t%s\n", + // "масштаб изображения без биннинга" + _("image scale without binning")); printf("\t-d,\t--dark\t\t\t%s\n", // "не открывать затвор при экспозиции (\"темновые\")" _("not open shutter when exposing (\"dark frames\")")); printf("\t-D,\t--display-image\t\t%s\n", // "Отобразить на экране полученное изображение" - _("Display last image")); + _("display last image")); printf("\t-E,\t--ether-subnet\t\t%s\n", // "Подсеть для поиска ethernet-камеры" - _("Subnet fot ethernet camera discovery")); + _("subnet fot ethernet camera discovery")); printf("\t-f,\t--no-flash\t\t%s\n", // "не засвечивать матрицу перед экспозицией" - _("Don't flash CCD chip before expose")); + _("don't flash CCD chip before expose")); printf("\t-F,\t--fan-speed=F\t\t%s\n", // "Установить скорость вентиляторов в F (0..3)" - _("Set fan speed to F (0..3)")); + _("set fan speed to F (0..3)")); printf("\t-g,\t--wheel-get\t\t%s\n", // получить сведения о турели _("get turret's parameters")); @@ -265,7 +277,7 @@ void usage(char *fmt, ...){ void parse_args(int argc, char **argv){ FNAME(); int i; - char short_options[] = "A:cdDE:fF:gG:H:h:I:i:LlM:N:n:O:o:P:p:Rr:SsTt:v:Ww:x:X:Y:"; + char short_options[] = "A:b:cC:dDE:fF:gG:H:h:I:i:LlM:N:n:O:o:P:p:Rr:SsTt:v:Ww:x:X:Y:"; struct option long_options[] = { /* { name, has_arg, flag, val }, где: * name - name of long parameter @@ -276,10 +288,12 @@ void parse_args(int argc, char **argv){ * !!! last string - for zeros !!! */ {"author", 1, 0, 'A'}, + {"defhdr", 1, 0, 'b'}, {"cooler-off", 0, 0, 'c'}, + {"imscale", 1, 0, 'C'}, {"dark", 0, 0, 'd'}, {"display-image",0, 0, 'D'}, - {"--ether-subnet",1,0, 'E'}, + {"ether-subnet",1, 0, 'E'}, {"no-flash", 0, 0, 'f'}, {"fan-speed", 1, 0, 'F'}, {"wheel-get", 0, 0, 'g'}, @@ -337,6 +351,9 @@ void parse_args(int argc, char **argv){ // "Автор программы: %s" info(_("Program author: %s"), author); break; + case 'b': + defhdr_filename = strdup(optarg); + break; case 'c': only_turret = FALSE; set_T = TRUE; @@ -344,6 +361,13 @@ void parse_args(int argc, char **argv){ info(_("Set cooler off")); cooler_off = TRUE; break; + case 'C': + imscale = atof(optarg); + if(imscale < 0.){ + // "IMSCALE должно быть больше нуля" + usage(_("IMSCALE should be greater than zero")); + } + break; case 'd': shutter = 0; // "Съемка темновых" @@ -427,7 +451,7 @@ void parse_args(int argc, char **argv){ break; case 'M': cammsgid = strdup(optarg); - info("MSG_ID: %s", cammsgid); + info("CAMMSGID: %s", cammsgid); break; case 'N': only_turret = FALSE; @@ -559,16 +583,18 @@ void parse_args(int argc, char **argv){ if(argc == 0){ save_image = FALSE; } - else{ + else if(!strchr(argv[0], '=') && !strchr(argv[0], ' ')){ // argv[0] is a filename outfile = argv[0]; argc--; argv++; } - if(argc > 0){ - // "Игнорирую аргумент[ы]:\n" - printf(_("Ignore argument[s]:\n")); + get_defhdrs(defhdr_filename); + if(argc > 0){ // additional headers + // "Дополнительные заголовки:\n" + info(_("Additional headers")); for (i = 0; i < argc; i++) - warnx("%s ", argv[i]); + info("%s ", argv[i]); } + add_morehdrs(argc, argv); if(Shtr != -1) only_turret = FALSE; } diff --git a/usage.h b/usage.h index 1d38718..6947858 100644 --- a/usage.h +++ b/usage.h @@ -61,7 +61,10 @@ extern int ,flipY ,histry ; -extern double temperature; +extern double + temperature + ,imscale +; extern bool only_T @@ -87,6 +90,7 @@ extern char ,*author ,*subnet ,*cammsgid + ,*defhdr_filename ; void usage(char *fmt, ...); void parse_args(int argc, char **argv);