From a84e6caf0c6e794dcbc98f4c578bb10bae940422 Mon Sep 17 00:00:00 2001 From: eddyem Date: Thu, 23 Jul 2015 13:51:09 +0300 Subject: [PATCH] init on github --- .gitignore | 6 + CMakeLists.txt | 64 ++ README | 16 + README-func | 157 ++++ bta_print.c | 138 ++++ bta_print.h | 8 + bta_shdata.h | 1159 ++++++++++++++++++++++++++++++ extern/fliusb-1.3.tgz | Bin 0 -> 8719 bytes extern/libfli-1.104.tgz | Bin 0 -> 89491 bytes locale/ru/LC_MESSAGES/takepic.mo | Bin 0 -> 5389 bytes locale/ru/ru.po | 401 +++++++++++ takepic.c | 503 +++++++++++++ takepic.h | 95 +++ usage.c | 331 +++++++++ usage.h | 39 + 15 files changed, 2917 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README create mode 100644 README-func create mode 100644 bta_print.c create mode 100644 bta_print.h create mode 100644 bta_shdata.h create mode 100644 extern/fliusb-1.3.tgz create mode 100644 extern/libfli-1.104.tgz create mode 100644 locale/ru/LC_MESSAGES/takepic.mo create mode 100644 locale/ru/ru.po create mode 100644 takepic.c create mode 100644 takepic.h create mode 100644 usage.c create mode 100644 usage.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e12707a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +*.bak +*.bck +*.o +.hg* +.dropbox.attr diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..48318d0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 2.6) +set(PROJ takepic) +project(${PROJ}) +set(VERSION "0.2.0") +set(CMAKE_COLOR_MAKEFILE ON) +if(DEFINED DEBUG) + add_definitions(-DEBUG) +endif() +if(DEFINED CMAKE_INSTALL_PREFIX AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local") + set(CMAKE_INSTALL_PREFIX "/usr") +endif() +message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") +#aux_source_directory(. SOURCES) +set(SOURCES takepic.c usage.c) +if(NOT DEFINED NOBTA) + set(SOURCES ${SOURCES} bta_print.c) + add_definitions(-DUSE_BTA) +endif() +set(LCPATH locale/ru) +set(CFLAGS -O3 -Wall -Werror -W -std=c99) +set(PO_FILE ${LCPATH}/messages.po) +set(MO_FILE ${LCPATH}/LC_MESSAGES/${PROJ}.mo) +set(RU_FILE ${LCPATH}/ru.po) +find_package(PkgConfig REQUIRED) +set(MODULES cfitsio>=3.0 fli>=1.71) +if(DEFINED USEPNG) + set(MODULES ${MODULES} libpng>=1.2) + add_definitions(-DUSEPNG) +endif() +pkg_check_modules(${PROJ} REQUIRED ${MODULES}) +if(DEFINED USERAW) + add_definitions(-DUSERAW) +endif() +add_executable(${PROJ} ${SOURCES} ${PO_FILE} ${MO_FILE}) +target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES}) +include_directories(${${PROJ}_INCLUDE_DIRS}) +link_directories(${${PROJ}_LIBRARY_DIRS}) +add_definitions(${CFLAGS} -DLOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/share/locale\" + -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\") + +# Installation of the program +INSTALL(FILES ${MO_FILE} DESTINATION "share/locale/ru/LC_MESSAGES") + #PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) +INSTALL(TARGETS ${PROJ} DESTINATION "bin") + #PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +# Script to be executed at installation time (kind of post-intallation script) to +# change the right accesses on the installed files +#INSTALL(SCRIPT inst.cmake) + +find_package(Gettext REQUIRED) +find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext) +if(NOT GETTEXT_XGETTEXT_EXECUTABLE OR NOT GETTEXT_MSGFMT_EXECUTABLE) + message(FATAL_ERROR "xgettext not found") +endif() +add_custom_command( + OUTPUT ${PO_FILE} + COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} --from-code=koi8-r ${SOURCES} -c -k_ -kN_ -o ${PO_FILE} + COMMAND sed 's/charset=UTF-8/charset=koi8-r/' ${PO_FILE} | enconv > tmp && mv -f tmp ${PO_FILE} + COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} -Uis ${RU_FILE} ${PO_FILE} + DEPENDS ${SOURCES}) +add_custom_command( + OUTPUT ${MO_FILE} + COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ${RU_FILE} -o ${MO_FILE} + DEPENDS ${RU_FILE}) diff --git a/README b/README new file mode 100644 index 0000000..e59b8d6 --- /dev/null +++ b/README @@ -0,0 +1,16 @@ +1. cmake . +2. make +3. [make install] or just copy file takepic wherever you want + +File bta_print.c needed to fill specific FITS keys for BTA telescope +If your want use this outside SAO RAS localnet, write: +1. cmake -DNOBTA=1 . +2. make ... + + +If you wish to save not only FITS, define: +* -DUSERAW=1 to save raw data +* -DUSEPNG=1 to save png data + +define +* -DEBUG=1 for debug info diff --git a/README-func b/README-func new file mode 100644 index 0000000..ac69b6f --- /dev/null +++ b/README-func @@ -0,0 +1,157 @@ +// переменные, типы + flidomain_t = METHOD | DEVICE; + // METHOD: FLIDOMAIN_PARALLEL_PORT, FLIDOMAIN_USB, FLIDOMAIN_SERIAL, FLIDOMAIN_INET; + // DEVICE: FLIDEVICE_CAMERA, FLIDOMAIN_FILTERWHEEL, FLIDOMAIN_FOCUSER. + + fliframe_t = FLI_FRAME_TYPE_NORMAL или FLI_FRAME_TYPE_DARK. + + flibitdepth_t = FLI_MODE_8BIT или FLI_MODE_16BIT. + + flishutter_t = FLI_SHUTTER_CLOSE, FLI_SHUTTER_OPEN, FLI_SHUTTER_EXTERNAL_TRIGGER, + FLI_SHUTTER_EXTERNAL_TRIGGER_LOW, and FLI_SHUTTER_EXTERNAL_TRIGGER HIGH. + + flibgflush_t = FLI_BGFLUSH_STOP and FLI_BGFLUSH_START. + + flichannel_t = FLI_TEMPERATURE_INTERNAL and FLI_TEMPERATURE_EXTERNAL. + + flidebug_t = FLIDEBUG_NONE, FLIDEBUG_INFO, FLIDEBUG_WARN, and FLIDEBUG_FAIL. + +// функции + + LIBFLIAPI FLICancelExposure(flidev_t dev); // отмена экспозиции + // return: 0 - успех, !0 - неудача + + LIBFLIAPI FLIClose(flidev_t dev); // закрыть устройство + + LIBFLIAPI FLIGetArrayArea(flidev_t dev, + long* ul_x, long* ul_y, long* lr_x, long* lr_y); // получить размер фрейма + // ul_x, ul_y - координаты верхнего левого угла + // lr_x, lr_y - к-ты правого нижнего угла + + LIBFLIAPI FLIFlushRow(flidev_t dev, long rows, long repeat); // сброс рядов + // rows - кол-во рядов для сброса, repeat - сколько раз подряд сбросить + + LIBFLIAPI FLIGetFWRevision(flidev_t dev, long* fwrev); // версия прошивки + LIBFLIAPI FLIGetHWRevision(flidev_t dev, long* hwrev); // версия железа + // fwrev - версия прошивки, hwrev - версия железа + + LIBFLIAPI FLIGetLibVersion(char* ver, size_t len); // версия библиотеки + // ver - буфер для версии, len - его длина + + LIBFLIAPI FLIGetModel(flidev_t dev, char* model, size_t len); // имя модели + // model - буфер, len - его длина + + LIBFLIAPI FLIGetPixelSize(flidev_t dev, + double* pixel x, double* pixel y); // размер пикселя в мкм + + LIBFLIAPI FLIGetVisibleArea(flidev_t dev, + long* ul_x, long* ul_y, long* lr_x, long* lr_y); // р-р видимой области + // к-ты аналогично FLIGetArrayArea + + LIBFLIAPI FLIOpen(flidev_t* dev, char* name, flidomain_t domain); // открыть + // name - имя ищ FLIList() + + LIBFLIAPI FLISetDebugLevel(char* host, flidebug_t level); // уровень отладки + // host игнорируется + + LIBFLIAPI FLISetExposureTime(flidev_t dev, long exptime); // время экспозиции + // exptime - в миллисекундах + + LIBFLIAPI FLISetHBin(flidev_t dev, long hbin); // гориз. биннинг + LIBFLIAPI FLISetVBin(flidev_t dev, long vbin); // верт. биннинг + // hbin = 1..16, vbin = 1..16 + + LIBFLIAPI FLISetFrameType(flidev_t dev, fliframe_t frametype); // темновой или обычный + + LIBFLIAPI FLISetImageArea(flidev_t dev, + long ul_x, long ul_y, long lr_x, long lr_y); // установить область к-т + // lr_x = ul_x+(lrx-ul_x)/hbin; + // lr_y = ul_y+(lry-ul_y)/vbin; + // lrx, lry - абс. координаты в желаемой области + + LIBFLIAPI FLIGetExposureStatus(flidev_t dev, long* timeleft); + // время до окончания экспозиции + + LIBFLIAPI FLISetTemperature(flidev_t dev, double temperature); // задать Т + // temperature - в градусах Цельсия, от -55 до +45 + + LIBFLIAPI FLIGetTemperature(flidev_t dev, double* temperature); // узнать Т + + LIBFLIAPI FLIGrabRow(flidev_t dev, void* buff, size_t width); // считать ряд + // buff - буфер, width - макс. ширина ряда (размер буфера) + // считывает очередной ряд с камеры + + LIBFLIAPI FLIExposeFrame(flidev_t dev); // начать накопление + + LIBFLIAPI FLISetBitDepth(flidev_t dev, flibitdepth_t bitdepth); // задать разрядность + + LIBFLIAPI FLISetNFlushes(flidev_t dev, long nflushes); // задать кол-во сбросов + // перед экспозицией + + LIBFLIAPI FLIReadIOPort(flidev_t dev, long* ioportset); // считать порт io + // ioportset - считанные данные + + LIBFLIAPI FLIWriteIOPort(flidev_t dev, long ioportset); // записать в io + + LIBFLIAPI FLIConfigureIOPort(flidev_t dev, long ioportset); // настройка + // функционал каждого контакта порта io зависит от значения ioportset + // 1 - выход, 0 - вход + + LIBFLIAPI FLILockDevice(flidev_t dev); // блокировка устройства + // для обеспечения монопольного доступа + LIBFLIAPI FLIUnlockDevice(flidev_t dev); + + LIBFLIAPI FLIControlShutter(flidev_t dev, flishutter_t shutter); // затвор + // FLI_SHUTTER_EXTERNAL_TRIGGER_LOW и FLI_SHUTTER_EXTERNAL_TRIGGER + // запускают экспозицию при наличии лог. нуля на io0 + // FLI_SHUTTER_EXTERNAL_TRIGGER_HIGH - запуск эксп. на лог1 на io0 + + LIBFLIAPI FLIControlBackgroundFlush(flidev_t dev, flibgflush_t bgflush); + // фоновый сброс + + LIBFLIAPI FLIList(flidomain_t domain, char*** names); + // список устройств из домена domain + LIBFLIAPI FLIFreeList(char** names); // очистить список names + + LIBFLIAPI FLISetFilterPos(flidev_t dev, long filter); + // установить фильтр в позицию filter + + LIBFLIAPI FLIGetFilterPos(flidev_t dev, long* filter); + // текущее положение фильтра + + LIBFLIAPI FLIGetStepsRemaining(flidev_t dev, long* steps); + // количество шагов, оставшихся до назначенной позиции + + LIBFLIAPI FLIGetFilterCount(flidev_t dev, long* filter); + // узнать кол-во фильтров + + LIBFLIAPI FLIStepMotorAsync(flidev_t dev, long steps); + LIBFLIAPI FLIStepMotor(flidev_t dev, long steps); + // передвинуть турель на заданное кол-во шагов + + LIBFLIAPI FLIGetStepperPosition(flidev_t dev, long* position); + // текущее положение ШД + +// функции для работы с фокусирующим устройством + LIBFLIAPI FLIHomeFocuser(flidev_t dev); + LIBFLIAPI FLIGetFocuserExtent(flidev_t dev, long* extent); + LIBFLIAPI FLIReadTemperature(flidev_t dev, flichannel_t channel, + double* temperature); + + LIBFLIAPI FLICreateList(flidomain_t domain); // создать список + LIBFLIAPI FLIDeleteList(void); // удалить список + LIBFLIAPI FLIListFirst(flidomain_t* domain, char* filename, + size_t fnlen, char* name, size_t namelen); // получить первое устройство из списка + // domain - домен устр-ва; + // filename - имя файла устр-ва; + // fnlen - длина буфера имени файла; + // name - название устр-ва; + // namelen - длина буфера названия + + LIBFLIAPI FLIListNext(flidomain_t* domain, char* filename, + size_t fnlen, char* name, size_t namelen); // получить следующее устр-во + + + + + diff --git a/bta_print.c b/bta_print.c new file mode 100644 index 0000000..8e2dc89 --- /dev/null +++ b/bta_print.c @@ -0,0 +1,138 @@ +/* Print some BTA NewACS data (or write to file) + * Usage: + * bta_print [time_step] [file_name] + * Where: + * time_step - writing period in sec., >=1.0 + * <1.0 - once and exit (default) + * file_name - name of file to write to, + * "-" - stdout (default) + */ +#include "bta_print.h" +#include "bta_shdata.h" + + +static char buf[1024]; +char *time_asc(double t){ + int h, m; + double s; + h = (int)(t/3600.); + m = (int)((t - (double)h*3600.)/60.); + s = t - (double)h*3600. - (double)m*60.; + h %= 24; + if(s>59) s=59; + sprintf(buf, "%dh:%02dm:%04.1fs", h,m,s); + return buf; +} + +char *angle_asc(double a){ + char s; + int d, min; + double sec; + if (a >= 0.) + s = '+'; + else{ + s = '-'; a = -a; + } + d = (int)(a/3600.); + min = (int)((a - (double)d*3600.)/60.); + sec = a - (double)d*3600. - (double)min*60.; + d %= 360; + if(sec>59.9) sec=59.9; + sprintf(buf, "%c%d:%02d':%04.1f''", s,d,min,sec); + return buf; +} + +#define CMNTSZ 79 +#define CMNT(...) snprintf(comment, CMNTSZ, __VA_ARGS__) +#define FTKEY(...) WRITEKEY(fp, __VA_ARGS__, comment) + +void write_bta_data(fitsfile *fp){ + char comment[CMNTSZ + 1]; + char *val; + double dtmp; + int i; + get_shm_block(&sdat, ClientSide); + if(!check_shm_block(&sdat)) return; + // TELESCOP / Telescope name + CMNT("Telescope name"); + FTKEY(TSTRING, "TELESCOP", "BTA 6m telescope"); + dtmp = S_time-EE_time; + // ST / sidereal time (hh:mm:ss.ms) + CMNT("Sidereal time: %s", time_asc(dtmp)); + FTKEY(TDOUBLE, "ST", &dtmp); + // UT / universal time (hh:mm:ss.ms) + CMNT("Universal time: %s", time_asc(M_time)); + FTKEY(TDOUBLE, "UT", &M_time); + CMNT("Julian date"); + FTKEY(TDOUBLE, "JD", &JDate); + + switch(Tel_Focus){ + default: + case Prime : + val = "Prime"; + // FOCUS / Focus of telescope (mm) + CMNT("Focus of telescope (mm)"); + FTKEY(TDOUBLE, "VAL_F", &val_F); + break; + case Nasmyth1 : val = "Nasmyth1"; break; + case Nasmyth2 : val = "Nasmyth2"; break; + } + CMNT("Observation focus"); + FTKEY(TSTRING, "FOCUS", val); + // EPOCH / Epoch of RA & DEC + time_t epoch = time(NULL); + strftime(comment, CMNTSZ, "%Y", gmtime(&epoch)); + i = atoi(comment); + CMNT("Epoch of RA & DEC"); + FTKEY(TINT, "EPOCH", &i); + CMNT("Current object R.A.: %s", time_asc(CurAlpha)); + // RA / Right ascention (HH MM SS) + FTKEY(TDOUBLE, "RA", &CurAlpha); + // DEC / Declination (DD MM SS) + CMNT("Current object Decl.: %s", angle_asc(CurDelta)); + FTKEY(TDOUBLE, "DEC", &CurDelta); + CMNT("Source R.A.: %s", time_asc(SrcAlpha)); + FTKEY(TDOUBLE, "S_RA", &SrcAlpha); + CMNT("Source Decl.: %s", angle_asc(SrcDelta)); + FTKEY(TDOUBLE, "S_DEC", &SrcDelta); + CMNT("Telescope R.A: %s", time_asc(val_Alp)); + FTKEY(TDOUBLE, "T_RA", &val_Alp); + CMNT("Telescope Decl.: %s", angle_asc(val_Del)); + FTKEY(TDOUBLE, "T_DEC", &val_Del); + // A / Azimuth + CMNT("Current object Azimuth: %s", angle_asc(tag_A)); + FTKEY(TDOUBLE, "A", &tag_A); + // Z / Zenith distance + CMNT("Current object Zenith: %s", angle_asc(tag_Z)); + FTKEY(TDOUBLE, "Z", &tag_Z); + // ROTANGLE / Field rotation angle + CMNT("Field rotation angle: %s", angle_asc(tag_P)); + FTKEY(TDOUBLE, "ROTANGLE", &tag_P); + + CMNT("Telescope A: %s", angle_asc(val_A)); + FTKEY(TDOUBLE, "VAL_A", &val_A); + CMNT("Telescope Z: %s", angle_asc(val_Z)); + FTKEY(TDOUBLE, "VAL_Z", &val_Z); + CMNT("Current P: %s", angle_asc(val_P)); + FTKEY(TDOUBLE, "VAL_P", &val_P); + + CMNT("Dome A: %s", angle_asc(val_D)); + FTKEY(TDOUBLE, "VAL_D", &val_D); + // OUTTEMP / Out temperature (C) + CMNT("Outern temperature, degC"); + FTKEY(TDOUBLE, "OUTTEMP", &val_T1); + // DOMETEMP / Dome temperature (C) + CMNT("In-dome temperature, degC"); + FTKEY(TDOUBLE, "DOMETEMP", &val_T2); + // MIRRTEMP / Mirror temperature (C) + CMNT("Mirror temperature, degC"); + // PRESSURE / Pressure (mmHg) + FTKEY(TDOUBLE, "MIRRTEMP", &val_T3); + CMNT("Pressure, mmHg"); + FTKEY(TDOUBLE, "PRESSURE", &val_B); + // WIND / Wind speed (m/s) + CMNT("Wind speed, m/s"); + FTKEY(TDOUBLE, "WIND", &val_Wnd); + CMNT("Humidity, %%"); + FTKEY(TDOUBLE, "HUM", &val_Hmd); +} diff --git a/bta_print.h b/bta_print.h new file mode 100644 index 0000000..6ddb506 --- /dev/null +++ b/bta_print.h @@ -0,0 +1,8 @@ +#ifndef __BTA_PRINT_H__ +#define __BTA_PRINT_H__ + +#include "takepic.h" + +void write_bta_data(fitsfile *fp); + +#endif // __BTA_PRINT_H__ diff --git a/bta_shdata.h b/bta_shdata.h new file mode 100644 index 0000000..2aec738 --- /dev/null +++ b/bta_shdata.h @@ -0,0 +1,1159 @@ +#pragma once +#ifndef __BTA_SHDATA_H__ +#define __BTA_SHDATA_H__ + +#define _XOPEN_SOURCE 501 +/* Основные определения и функции поддержки межпрограммного интерфейса */ +/* Возможные внешние определения: */ +/* BTA_MODULE - при исп-и в доп. C-модулях (не в главн.программе) */ +/* SHM_OLD_SIZE - для генерации предыдущей весии структуры БТА-данных */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __GNUC_PREREQ(4,2) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-braces" +#pragma GCC diagnostic ignored "-Wsequence-point" +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" +#pragma GCC diagnostic ignored "-Wimplicit-function-declaration" +#endif + +#define uint __uint32_t + +struct SHM_Block { /* описание блока разделяемой памяти */ + union { + char name[5]; /* ключ идентефикации сегмента памяти */ + key_t code; + } key; + int size; /* размер используемой части в байтах */ + int maxsize; /* размер при создании ("с запасом" для будущих версий) */ + int mode; /* режим доступа (rwxrwxrwx) */ + int atflag; /* режим подсоединения (SHM_RDONLY или 0) */ + void (*init)(); /* процедура инициализации */ + int (*check)(); /* процедура проверки */ + void (*close)(); /* процедура отсоединения */ + int side; /* тип подсоединения: Клиент/Сервер */ + int id; /* дескриптор подсоединения */ + unsigned char *addr; /* адрес подсоединения */ +}; + +struct CMD_Queue { /* описание очереди (канала) команд */ + union { + char name[5]; /* ключ идентефикации очереди */ + key_t code; + } key; + int mode; /* режим доступа (rwxrwxrwx) */ + int side; /* тип подсоединения: Клиент/Сервер (Sender/Receiver)*/ + int id; /* дескриптор подсоединения */ + uint acckey; /* ключ доступа (для передачи Клиент->Сервер) */ +}; + +#ifndef BTA_MODULE +/* канал команд главного операторского интерфейса (Level5)*/ +struct CMD_Queue mcmd = {{'M','c','m','d',0},0200,0,-1,0}; +/* канал передачи операторских (привелегированных) команд (Level4)*/ +struct CMD_Queue ocmd = {{'O','c','m','d',0},0200,0,-1,0}; +/* канал передачи пользовательских (непривелегированных) команд (Level2/3)*/ +struct CMD_Queue ucmd = {{'U','c','m','d',0},0200,0,-1,0}; +#else +extern struct CMD_Queue mcmd; +extern struct CMD_Queue ocmd; +extern struct CMD_Queue ucmd; +#endif + +static void send_cmd_noarg(int); +static void send_cmd_str(int, char *); +static void send_cmd_i1(int, int); +static void send_cmd_i2(int, int, int); +static void send_cmd_i3(int, int, int, int); +static void send_cmd_i4(int, int, int, int, int); +static void send_cmd_d1(int, double); +static void send_cmd_d2(int, double, double); +static void send_cmd_i1d1(int, int, double); +static void send_cmd_i2d1(int, int, int, double); +static void send_cmd_i3d1(int, int, int, int, double); + +/* список команд */ +/* имя код аргументы тип */ +#define StopTel 1 /* останов телескопа */ +#define StopTeleskope() send_cmd_noarg( 1 ) /* опер. */ +#define StartHS 2 /* старт привода наведения */ +#define StartHightSpeed() send_cmd_noarg( 2 ) /* опер/тст*/ +#define StartLS 3 /* старт привода ведения */ +#define StartLowSpeed() send_cmd_noarg( 3 ) /* опер/тст*/ +#define SetTmr 4 /* уст. Ch7_15 или SysTimer */ +#define SetTimerMode(T) send_cmd_i1 ( 4, (int)(T)) /* М.опер. */ +#define SetModMod 5 /* уст. режим моделирования */ +#define SetModelMode(M) send_cmd_i1 ( 5, (int)(M)) /* М.опер. */ +#define SetCodA 6 /* код скорости по A */ +#define SetPKN_A(iA,sA) send_cmd_i2 ( 6, (int)(iA),(int)(sA)) /* опер/тст*/ +#define SetCodZ 7 /* код скорости по Z */ +#define SetPKN_Z(iZ) send_cmd_i1 ( 7, (int)(iZ)) /* опер/тст*/ +#define SetCodP 8 /* код скорости по P */ +#define SetPKN_P(iP) send_cmd_i1 ( 8, (int)(iP)) /* опер/тст*/ +#define SetVA 9 /* уст. скорость по A */ +#define SetSpeedA(vA) send_cmd_d1 ( 9, (double)(vA)) /* опер/тст*/ +#define SetVZ 10 /* уст. скорость по Z */ +#define SetSpeedZ(vZ) send_cmd_d1 (10, (double)(vZ)) /* опер/тст*/ +#define SetVP 11 /* уст. скорость по P */ +#define SetSpeedP(vP) send_cmd_d1 (11, (double)(vP)) /* опер/тст*/ +#define SetAD 12 /* зап.новые координаты R.A.и Decl */ +#define SetRADec(Alp,Del) send_cmd_d2 (12, (double)(Alp),(double)(Del))/* польз.*/ +#define SetAZ 13 /* зап.координаты азимут и зен.расст.*/ +#define SetAzimZ(A,Z) send_cmd_d2 (13, (double)(A),(double)(Z))/* польз.*/ +#define GoToAD 14 /* старт наведения на объект (по R.A.и Decl)*/ +#define GoToObject() send_cmd_noarg(14 ) /* опер. */ +#define MoveToAD 15 /* переезд на объект (по R.A.и Decl)*/ +#define MoveToObject() send_cmd_noarg(15 ) /* польз.*/ +#define GoToAZ 16 /* наведение по положению (по A Z)*/ +#define GoToAzimZ() send_cmd_noarg(16 ) /* опер. */ +#define WriteAZ 17 /* установка A и Z для FullModel*/ +#define WriteModelAZ() send_cmd_noarg(17 ) /* опер. */ +#define SetModP 18 /* уст. режим использования P2 */ +#define SetPMode(pmod) send_cmd_i1 (18, (int)(pmod)) /* польз.*/ +#define P2Move 19 /* вкл./выкл. (+-1,0) движение P2 */ +#define MoveP2(dir) send_cmd_i1 (19, (int)(dir)) /* польз.*/ +#define FocMove 20 /* вкл./выкл. (+-2,+-1,0) движение фокуса */ +#define MoveFocus(speed,time) send_cmd_i1d1(20,(int)(speed),(double)(time)) /* польз.*/ +#define UsePCorr 21 /* режим учета поправок положения (СКН) */ +#define SwitchPosCorr(pc_flag) send_cmd_i1 (21, (int)(pc_flag)) /* опер. */ +#define SetTrkFlags 22 /* уст. флагов режима слежения */ +#define SetTrkOkMode(trk_flags) send_cmd_i1 (22, (int)(trk_flags)) /* опер.*/ +#define SetTFoc 23 /* уст.фокуса: 0-ПФ, 1-Н1, 2-Н2 */ +#define SetTelFocus(N) send_cmd_i1 ( 23, (int)(N)) /* опер. */ +#define SetVAD 24 /* уст.ск.собсв.дв-я объекта по R.A.и Decl */ +#define SetVelAD(VAlp,VDel) send_cmd_d2 (24, (double)(VAlp),(double)(VDel))/* опер.*/ +#define SetRevA 25 /* уст. режим "обхода" азимута */ +#define SetAzRevers(amod) send_cmd_i1 (25, (int)(amod)) /* польз.*/ +#define SetVP2 26 /* уст.скор..дв-я P2 (для ДБУ) */ +#define SetVelP2(vP2) send_cmd_d1 (26, (double)(vP2)) /* польз.*/ +#define SetTarg 27 /* уст. цели наведения */ +#define SetSysTarg(Targ) send_cmd_i1 (27, (int)(Targ)) /* опер.*/ +#define SendMsg 28 /* размещение сообщения (всем клиентам и в протокол) */ +#define SendMessage(Mesg) send_cmd_str (28, (char *)(Mesg)) /* польз.*/ +#define CorrAD 29 /* коррекция координат R.A.и Decl */ +#define DoADcorr(dAlp,dDel) send_cmd_d2 (29, (double)(dAlp),(double)(dDel))/* польз.*/ +#define CorrAZ 30 /* коррекция координат A и Z*/ +#define DoAZcorr(dA,dZ) send_cmd_d2 (30, (double)(dA),(double)(dZ))/* польз.*/ +#define SetVCAZ 31 /* уст.скор.коррекции по A и Z*/ +#define SetVCorr(vA,vZ) send_cmd_d2 (31, (double)(vA),(double)(vZ))/* польз.*/ +#define P2MoveTo 32 /* переезд P2 по времени */ +#define MoveP2To(vP2,time) send_cmd_d2 (32, (double)(vP2),(double)(time))/* польз.*/ +#define GoToTD 33 /* старт наведения на стационар (по t и Decl)*/ +#define GoToSat() send_cmd_noarg (33 ) /* опер..*/ +#define MoveToTD 34 /* переезд на стационар (по t и Decl)*/ +#define MoveToSat() send_cmd_noarg (34 ) /* польз.*/ +#define NullCom 35 /* пустая команда (для синхронизаций?) */ +#define SyncCom() send_cmd_noarg (35 ) /* опер. */ +#define StartTel 36 /* кнопка "Пуск" телескопа */ +#define StartTeleskope() send_cmd_noarg(36 ) /* опер. */ +#define SetTMod 37 /* уст. режимы работы телескопа */ +#define SetTelMode(M) send_cmd_i1 ( 37, (int)(M)) /* М.опер. */ +#define TelOn 38 /* кнопка Вкл. Масло, ЭМУ и т.д.*/ +#define TeleskopeOn() send_cmd_noarg(38 ) /* М.опер. */ +#define SetModD 39 /* уст. режим использования купола */ +#define SetDomeMode(dmod) send_cmd_i1 (39, (int)(dmod)) /* М.опер.*/ +#define DomeMove 40 /* вкл./выкл. (+-1+-2,+-3,0) движение купола */ +#define MoveDome(speed,time) send_cmd_i1d1(40,(int)(speed),(double)(time)) /* опер.*/ +#define SetPass 41 /* уст. пароль уровня доступа */ +#define SetPasswd(LPass) send_cmd_str (41, (char *)(LPass)) /* М.опер.*/ +#define SetLevC 42 /* уст. код уровня доступа */ +#define SetLevCode(Nlev,Cod) send_cmd_i2(42, (int)(Nlev),(int)(Cod)) /* М.опер.*/ +#define SetLevK 43 /* уст. ключ уровня доступа */ +#define SetLevKey(Nlev,Key) send_cmd_i2(43, (int)(Nlev),(int)(Key)) /* М.опер.*/ +#define SetNet 44 /* уст. маску и адрес подсети */ +#define SetNetAcc(Mask,Addr) send_cmd_i2(44, (int)(Mask),(int)(Addr)) /* М.опер.*/ +#define SetMet 45 /* ввод метео данных */ +#define SetMeteo(m_id,m_val) send_cmd_i1d1(45,(int)(m_id),(double)(m_val)) /* опер.*/ +#define TurnMetOff 46 /* отмена исп. метео данных */ +#define TurnMeteoOff(m_id) send_cmd_i1 (46, (int)(m_id)) /* опер.*/ +#define SetDUT1 47 /* уст.попр.времени(IERS DUT1=UT1-UTC) */ +#define SetDtime(dT) send_cmd_d1 (47, (double)(dT)) /* М.опер.*/ +#define SetPM 48 /* уст.полож.полюса(IERS polar motion)*/ +#define SetPolMot(Xp,Yp) send_cmd_d2 (48, (double)(Xp),(double)(Yp)) /* М.опер.*/ +#define GetSEW 49 /* прочитать SEW параметр */ +#define GetSEWparam(Ndrv,Indx,Cnt) send_cmd_i3(49,(int)(Ndrv),(int)(Indx),(int)(Cnt)) /* M.опер.*/ +#define PutSEW 50 /* записать SEW параметр */ +#define PutSEWparam(Ndrv,Indx,Key,Val) send_cmd_i4(50,(int)(Ndrv),(int)(Indx),(int)(Key),(int)(Val)) /* M.опер.*/ +#define SetLocks 51 /* установка блокировок управления узлами */ +#define SetLockFlags(f) send_cmd_i1 (SetLocks, (int)(f)) /* M.опер.*/ +#define ClearLocks 52 /* отмена блокировок управления узлами */ +#define ClearLockFlags(f) send_cmd_i1 (ClearLocks, (int)(f)) /* M.опер.*/ +#define SetRKbits 53 /* Установка доп.битов PEP-RK */ +#define AddRKbits(f) send_cmd_i1 (SetRKbits, (int)(f)) /* M.опер.*/ +#define ClrRKbits 54 /* Очистка доп.битов PEP-RK */ +#define ClearRKbits(f) send_cmd_i1 (ClrRKbits, (int)(f)) /* M.опер.*/ +#define SetSEWnd 55 /* уст.номер SEW-движка купола (для индикации)*/ +#define SetDomeDrive(ND) send_cmd_i1 (SetSEWnd, (int)(ND)) /* М.опер.*/ +#define SEWsDome 56 /* Вкл./Выкл. SEW-движков купола */ +#define DomeSEW(OnOff) send_cmd_i1 (SEWsDome, (int)(OnOff)) /* М.опер.*/ + + +/* структура данных алгоритма управления (распределение "глобальной области") */ +#define BTA_Data_Ver 2 +#pragma pack(4) +//struct __attribute__((packed)) BTA_Data { +struct BTA_Data { + int magic; /* код опознания структуры */ + int version; /* номер версии структуры = BTA_Data_Ver*/ + int size; /* размер структуры = sizeof(struct BTA_Data)*/ + int pid; +#define ServPID (sdt->pid) /*номер процесса гл.упр.программы */ + + /* режимы работы */ + int model; +#define UseModel (sdt->model) /* вариант использования моделирования */ +#define NoModel 0 /* отключено */ +#define CheckModel 1 /* привода контролируются по модели */ +#define DriveModel 2 /* моделирование приводов и "слепое" управление без реальных датчиков */ +#define FullModel 3 /* полное моделирование без телескопа */ + int timer; +#define ClockType (sdt->timer) /* какие часы используются */ +#define Ch7_15 0 /* Внутр.часы упр.программы с синхронизацией по Ч7-15 */ +#define SysTimer 1 /* Таймер системы (неизвестно синхронизированный или нет) */ +#define ExtSynchro 2 /* Работает синхронизация таймера системы внешней программой (bta_time или xntpd)*/ + int system; +#define Sys_Mode (sdt->system) /* режим работы системы */ +#define SysStop 0 /* Останов */ +#define SysWait 1 /* Ожидание старта (наведения) */ +#define SysPointAZ 2 /* Наведение по положению (по A Z)*/ +#define SysPointAD 3 /* Наведение на объект (по R.A.и Decl)*/ +#define SysTrkStop 4 /* Ведение: ожидание старта */ +#define SysTrkStart 5 /* Ведение: разгон до номин.скорости (объекта)*/ +#define SysTrkMove 6 /* Ведение: переезд на объект */ +#define SysTrkSeek 7 /* Ведение: слежение за объектом */ +#define SysTrkOk 8 /* Ведение: рассогласования в допуске */ +#define SysTrkCorr 9 /* Ведение: коррекция положения */ +#define SysTest 10 /* Тестирование */ + int sys_target; +#define Sys_Target (sdt->sys_target) /* цель наведения */ +#define TagPosition 0 /* Положение A/Z */ +#define TagObject 1 /* Объект Alpha/Delta */ +#define TagNest 2 /* Положение "Гнездо" */ +#define TagZenith 3 /* Положение "Зенит" */ +#define TagHorizon 4 /* Положение "Горизонт" */ +#define TagStatObj 5 /* "Стационар" t/Delta */ + + int tel_focus; +#define Tel_Focus (sdt->tel_focus) /* тип фокуса телескопа: 0-ПФ, 1-Н1, 2-Н2 */ +#define Prime 0 +#define Nasmyth1 1 +#define Nasmyth2 2 + double pc_coeff[8]; +#define PosCor_Coeff (sdt->pc_coeff) /* коэф-ты СКН для тек.фокуса */ + + /* состояние телескопа */ +#define Stopping 0 /* Останов */ +#define Pointing 1 /* Наведение */ +#define Tracking 2 /* Ведение */ + int tel_state; +#define Tel_State (sdt->tel_state) /* реально отрабатываемое */ + int req_state; +#define Req_State (sdt->req_state) /* затребованное программой */ + int tel_hard_state; +#define Tel_Hardware (sdt->tel_hard_state) /* состояние УСО */ +#define Hard_Off 0 /* питание выключено */ +#define Hard_On 1 /* включено */ + + /* режимы работы телескопа */ + int tel_mode; +#define Tel_Mode (sdt->tel_mode) +#define Automatic 0 /* "Автомат" - нормальный режим*/ +#define Manual 1 /* "П/авт.упр." - пультовой режим и в нем:*/ +#define ZenHor 2 /* "Зенит-Горизонт" - работа при Z<5 и Z>80*/ +#define A_Move 4 /* ручное движение A */ +#define Z_Move 8 /* --- "" --- Z */ +#define Balance 0x10 /* балансировка трубы */ + + /* вкл./выкл. режим "обхода" азимута */ + int az_mode; +#define Az_Mode (sdt->az_mode) +#define Rev_Off 0 /* нормальное наведение на ближайшее положение по азимуту */ +#define Rev_On 1 /* наведение с перегоном на 360град. */ + + /* работа P2 */ + int p2_state; +#define P2_State (sdt->p2_state) /* реальное состояние привода P2 */ +#define P2_Off 0 /* Стоит */ +#define P2_On 1 /* Ведет */ +#define P2_Plus 2 /* быстро едет в + */ +#define P2_Minus -2 /* быстро едет в - */ + int p2_req_mode; +#define P2_Mode (sdt->p2_req_mode) /* режим использования P2 (пока: Вкл/Выкл)*/ + + /* состояние привода фокуса */ + int focus_state; +#define Foc_State (sdt->focus_state) +#define Foc_Off 0 /* Стоит */ +#define Foc_Lplus 1 /* медл. едет в + */ +#define Foc_Lminus -1 /* медл. едет в - */ +#define Foc_Hplus 2 /* быстро едет в + */ +#define Foc_Hminus -2 /* быстро едет в - */ + + /* состояние привода купола */ + int dome_state; +#define Dome_State (sdt->dome_state) +#define D_On 7 /* Автоматическое согласование с телескопом */ +#define D_Off 0 /* Стоит */ +#define D_Lplus 1 /* медл. едет в + */ +#define D_Lminus -1 /* медл. едет в - */ +#define D_Mplus 2 /* сред.скор. в + */ +#define D_Mminus -2 /* сред.скор. в - */ +#define D_Hplus 3 /* быстро едет в + */ +#define D_Hminus -3 /* быстро едет в - */ + +/* учет поправок положения (СКН) */ + int pcor_mode; +#define Pos_Corr (sdt->pcor_mode) /* коррекция положения объекта по A/Z: Вкл/Выкл*/ +#define PC_Off 0 /* Выкл. */ +#define PC_On 1 /* Вкл. */ + +/* флаги вкл/выкл. вариантов режима слежения */ + int trkok_mode; +#define TrkOk_Mode (sdt->trkok_mode) +#define UseDiffVel 1 /* определение&учет поправок реальной скорости приводов (~изодором)*/ +#define UseDiffAZ 2 /* слежение по рассогласованию (иначе уст.рассчетн.скоростей) */ +#define UseDFlt 4 /* вкл. цифрового фильтра рассогласований */ + + /* введенные значения */ + double i_alpha, i_delta; +#define InpAlpha (sdt->i_alpha) /* введенная координата R.A. (sec) */ +#define InpDelta (sdt->i_delta) /* -- " -- Decl. (") */ + double s_alpha, s_delta; +#define SrcAlpha (sdt->s_alpha) /* исходная координата R.A. (sec) */ +#define SrcDelta (sdt->s_delta) /* -- " -- Decl. (") */ + double v_alpha, v_delta; +#define VelAlpha (sdt->v_alpha) /* ск.собсв.дв-я объекта по R.A. (sec/сек) */ +#define VelDelta (sdt->v_delta) /* -- " -- Decl. ("/сек) */ + double i_azim, i_zdist; +#define InpAzim (sdt->i_azim) /* для наведения по азимуту (") */ +#define InpZdist (sdt->i_zdist) /* -- " -- зен.расст. (") */ + + /* рассчетные значения */ + double c_alpha, c_delta; +#define CurAlpha (sdt->c_alpha) /* текущая координата R.A. (sec) */ +#define CurDelta (sdt->c_delta) /* -- " -- Decl. (") */ + double tag_a, tag_z, tag_p; +#define tag_A (sdt->tag_a) /* текущий A (") объекта */ +#define tag_Z (sdt->tag_z) /* - " - Z (") - " - */ +#define tag_P (sdt->tag_p) /* - " - P (") - " - */ + double pcor_a, pcor_z, refr_z; +#define pos_cor_A (sdt->pcor_a) /* поправка положения объекта по A (") */ +#define pos_cor_Z (sdt->pcor_z) /* - " - - " - по Z (") */ +#define refract_Z (sdt->refr_z) /* поправка за рефракцию для объекта (") */ + double tcor_a, tcor_z, tref_z; +#define tel_cor_A (sdt->tcor_a) /* поправка обр.пересчета положения телескопа по A (") */ +#define tel_cor_Z (sdt->tcor_z) /* - " - - " - - " - по Z (") */ +#define tel_ref_Z (sdt->tref_z) /* поправка обр.пересчета за рефракцию (") */ + double diff_a, diff_z, diff_p; +#define Diff_A (sdt->diff_a) /* рассогл-е(осталось ехать) по A (") */ +#define Diff_Z (sdt->diff_z) /* - " - - " - Z (") */ +#define Diff_P (sdt->diff_p) /* - " - - " - P (") */ + double vbasea,vbasez,vbasep; +#define vel_objA (sdt->vbasea) /* базовая скорость объекта по A ("/сек) */ +#define vel_objZ (sdt->vbasez) /* - " - - " - Z - " - */ +#define vel_objP (sdt->vbasep) /* - " - - " - P - " - */ + double diffva,diffvz,diffvp; +#define diff_vA (sdt->diffva) /* поправка реальной скорости привода по азимуту */ +#define diff_vZ (sdt->diffvz) /* -- "" -- -- "" -- по Z */ +#define diff_vP (sdt->diffvp) /* -- "" -- -- "" -- по P */ + double speeda,speedz,speedp; +#define speedA (sdt->speeda) /* скорость по A ("/сек) для управления приводом */ +#define speedZ (sdt->speedz) /* - " - Z - " - */ +#define speedP (sdt->speedp) /* - " - P - " - */ + double m_time_precip; +#define Precip_time (sdt->m_time_precip)/* момент времени появления осадков (precipitations)*/ + unsigned char reserve[16]; +#define Reserve (sdt->reserve) /* свободное место */ + double rspeeda, rspeedz, rspeedp; +#define req_speedA (sdt->rspeeda) /* скорость ("/сек) выданная на привод A */ +#define req_speedZ (sdt->rspeedz) /* - " - Z */ +#define req_speedP (sdt->rspeedp) /* - " - P */ + double simvela, simvelz, simvelp, simvelf, simveld; +#define mod_vel_A (sdt->simvela) /* скорость по A ("/сек) модельная */ +#define mod_vel_Z (sdt->simvelz) /* - " - Z - " - */ +#define mod_vel_P (sdt->simvelp) /* - " - P - " - */ +#define mod_vel_F (sdt->simvelf) /* - " - F - " - */ +#define mod_vel_D (sdt->simvelf) /* - " - D - " - */ + + + /* результаты измерения датчиков и рассчитанные по ним значения */ + uint kost; +#define code_KOST (sdt->kost) /* сост. телескопа и ручной коррекции */ + /* 0x8000 - азимут положительный */ + /* 0x4000 - отработка вкл. */ + /* 0x2000 - режим ведения */ + /* 0x1000 - отработка P2 вкл.*/ + /* 0x01F0 - ск.корр. 0.2 0.4 1.0 2.0 5.0("/сек) */ + /* 0x000F - напр.корр. +Z -Z +A -A */ + double m_time, s_time, l_time; +#define M_time (sdt->m_time) /* текущее московское время (теперь UTC!)*/ +#define S_time (sdt->s_time) /* текущее звездное время */ +#define L_time (sdt->l_time) /* время работы программы */ + uint ppndd_a, ppndd_z, ppndd_p, ppndd_b; +#define ppndd_A (sdt->ppndd_a) /* код датчика ППНДД (грубого отсчета) A */ +#define ppndd_Z (sdt->ppndd_z) /* - "" - Z */ +#define ppndd_P (sdt->ppndd_p) /* - "" - P */ +#define ppndd_B (sdt->ppndd_b) /* код датчика ППНДД давления */ + uint dup_a, dup_z, dup_p, dup_f, dup_d; +#define dup_A (sdt->dup_a) /* код Грея датчика ДУП (точного отсчета) A */ +#define dup_Z (sdt->dup_z) /* - "" - Z */ +#define dup_P (sdt->dup_p) /* - "" - P */ +#define dup_F (sdt->dup_f) /* код Грея датчика ДУП фокуса телескопа */ +#define dup_D (sdt->dup_d) /* код Грея датчика ДУП положения купола */ + uint low_a, low_z, low_p, low_f, low_d; +#define low_A (sdt->low_a) /* 14р-в дв.кода точного отсчета A */ +#define low_Z (sdt->low_z) /* - "" - Z */ +#define low_P (sdt->low_p) /* - "" - P */ +#define low_F (sdt->low_f) /* код отсчета фокуса телескопа */ +#define low_D (sdt->low_d) /* код отсчета положения купола */ + uint code_a, code_z, code_p, code_b, code_f, code_d; +#define code_A (sdt->code_a) /* 23р-в дв.кода отсчета A */ +#define code_Z (sdt->code_z) /* - "" - Z */ +#define code_P (sdt->code_p) /* - "" - P */ +#define code_B (sdt->code_b) /* код давления */ +#define code_F (sdt->code_f) /* код отсчета фокуса телескопа */ +#define code_D (sdt->code_d) /* код отсчета положения купола */ + uint adc[8]; +#define ADC(N) (sdt->adc[(N)]) /* коды 8-ми каналов АЦП PCL818 */ +#define code_T1 ADC(0) /* код датчика наруж. температуры*/ +#define code_T2 ADC(1) /* код датчика температуры под куп.*/ +#define code_T3 ADC(2) /* код датчика температуры зеркала */ +#define code_Wnd ADC(3) /* код датчика ветра */ + double val_a, val_z, val_p, val_b, val_f, val_d; + double val_t1, val_t2, val_t3, val_wnd; +#define val_A (sdt->val_a) /* отсчет A (") */ +#define val_Z (sdt->val_z) /* - " - Z (") */ +#define val_P (sdt->val_p) /* - " - P (") */ +#define val_B (sdt->val_b) /* давлениe (мм.рт.ст.)*/ +#define val_F (sdt->val_f) /* фокус телескопа (мм) */ +#define val_D (sdt->val_d) /* положение купола (") */ +#define val_T1 (sdt->val_t1) /* наруж. температура (гр.)*/ +#define val_T2 (sdt->val_t2) /* температура под куп.(гр.)*/ +#define val_T3 (sdt->val_t3) /* температура зеркала (гр.)*/ +#define val_Wnd (sdt->val_wnd) /* ветер (м/сек)*/ + double val_alp, val_del; +#define val_Alp (sdt->val_alp) /* обратный пересчет R.A. (sec) */ +#define val_Del (sdt->val_del) /* -- " -- Decl. (") */ + + double vel_a, vel_z, vel_p, vel_f, vel_d; +#define vel_A (sdt->vel_a) /* скорость по A ("/сек) измеренная */ +#define vel_Z (sdt->vel_z) /* - " - Z - " - */ +#define vel_P (sdt->vel_p) /* - " - P - " - */ +#define vel_F (sdt->vel_f) /* - " - F - " - */ +#define vel_D (sdt->vel_d) /* - " - D - " - */ + + /* очередь последних системных сообщений */ +#define MesgNum 3 +#define MesgLen 39 + //struct __attribute__((packed)) SysMesg { + struct SysMesg { + int seq_num; + char type; +#define MesgEmpty 0 +#define MesgInfor 1 +#define MesgWarn 2 +#define MesgFault 3 +#define MesgLog 4 + char text[MesgLen]; + } sys_msg_buf[MesgNum]; +#define Sys_Mesg(N) (sdt->sys_msg_buf[N]) + + /* управление доступом */ + /* коды установки уровней доступа для клиентов */ + uint code_lev1,code_lev2,code_lev3,code_lev4,code_lev5; +#define code_Lev1 (sdt->code_lev1) /* "удаленный наблюдатель" - только информация */ +#define code_Lev2 (sdt->code_lev2) /* "местный наблюдатель" - + ввод координат */ +#define code_Lev3 (sdt->code_lev3) /* "главный наблюдатель" - + A/Z-корр-я, упр.P2/F */ +#define code_Lev4 (sdt->code_lev4) /* "оператор" - + пуск/стоп телеск., тестирование */ +#define code_Lev5 (sdt->code_lev5) /* "главный оператор" - все операции */ + /* ограничение сетевого доступа */ + uint netmask, netaddr, acsmask, acsaddr; +#define NetMask (sdt->netmask) /* маска подсети (обычно: 255.255.255.0) */ +#define NetWork (sdt->netaddr) /* адрес подсети (например: 192.168.3.0) */ +#define ACSMask (sdt->acsmask) /* маска АСУ-сети (например: 255.255.255.0) */ +#define ACSNet (sdt->acsaddr) /* адрес АСУ-сети (например: 192.168.13.0) */ + + /* ввод метео-данных */ + int meteo_stat; +#define MeteoMode (sdt->meteo_stat) /* флаги датчиков и ввода данных*/ +#define INPUT_B 1 /* давление *//* флаги ручного ввода метео данных */ +#define INPUT_T1 2 /* T-наружная */ +#define INPUT_T2 4 /* T-подкупольная */ +#define INPUT_T3 8 /* T-зеркала */ +#define INPUT_WND 0x10 /* ветер */ +#define INPUT_HMD 0x20 /* влажность */ +#define SENSOR_B (INPUT_B <<8) /* флаги внешних метео-датчиков (e.g.по CAN-шине)*/ +#define SENSOR_T1 (INPUT_T1 <<8) +#define SENSOR_T2 (INPUT_T2 <<8) +#define SENSOR_T3 (INPUT_T3 <<8) +#define SENSOR_WND (INPUT_WND<<8) +#define SENSOR_HMD (INPUT_HMD<<8) +#define ADC_B (INPUT_B <<16) /* флаги считывания с АЦП упр.компутера */ +#define ADC_T1 (INPUT_T1 <<16) +#define ADC_T2 (INPUT_T2 <<16) +#define ADC_T3 (INPUT_T3 <<16) +#define ADC_WND (INPUT_WND<<16) +#define ADC_HMD (INPUT_HMD<<16) +#define NET_B (INPUT_B <<24) /* флаги получения данных с метеостанции по сети */ +#define NET_T1 (INPUT_T1 <<24) +#define NET_WND (INPUT_WND<<24) +#define NET_HMD (INPUT_HMD<<24) + double inp_b, inp_t1, inp_t2, inp_t3, inp_wnd; +#define inp_B (sdt->inp_b) /* давлениe (мм.рт.ст.)*/ +#define inp_T1 (sdt->inp_t1) /* наруж. температура (гр.)*/ +#define inp_T2 (sdt->inp_t2) /* температура под куп.(гр.)*/ +#define inp_T3 (sdt->inp_t3) /* температура зеркала (гр.)*/ +#define inp_Wnd (sdt->inp_wnd) /* ветер (м/сек)*/ + + double temper, press; +#define Temper (sdt->temper) /* темрература используемая для рефракции */ +#define Pressure (sdt->press) /* давление используемое для рефракции */ + double m_time10, m_time15; +#define Wnd10_time (sdt->m_time10) /* момент времени порыва >=10м/сек*/ +#define Wnd15_time (sdt->m_time15) /* - " - - " - - " - >=15м/сек*/ + + /* IERS DUT1 (источник: ftp://maia.usno.navy.mil/ser7/ser7.dat) */ + double dut1; +#define DUT1 (sdt->dut1) /* поправка ср.солнечного времени: DUT1 = UT1-UTC */ + + double a_time, z_time, p_time; +#define A_time (sdt->a_time) /* момент считывания датчика A */ +#define Z_time (sdt->z_time) /* - " - - " - - " - Z */ +#define P_time (sdt->p_time) /* - " - - " - - " - P */ + + double speedain, speedzin, speedpin; +#define speedAin (sdt->speedain) /* постоянная скорость уст-я по A */ +#define speedZin (sdt->speedzin) /* постоянная скорость уст-я по Z */ +#define speedPin (sdt->speedpin) /* постоянная скорость уст-я по P2*/ + + double acc_a, acc_z, acc_p, acc_f, acc_d; +#define acc_A (sdt->acc_a) /* ускорение по A ("/сек^2) */ +#define acc_Z (sdt->acc_z) /* - " - Z - " - */ +#define acc_P (sdt->acc_p) /* - " - P - " - */ +#define acc_F (sdt->acc_f) /* - " - F - " - */ +#define acc_D (sdt->acc_d) /* - " - D - " - */ + + uint code_sew; +#define code_SEW (sdt->code_sew) /* код спец.доступа к SEW-контроллерам */ + +/* параметры SEW-контроллеров */ +//struct __attribute__((packed)) SEWdata { +struct SEWdata { + int status; + double set_speed; + double mes_speed; + double current; + int index; + union { + unsigned char b[4]; + __uint32_t l; + } value; +} sewdrv[3]; +#define statusSEW(Drv) (sdt->sewdrv[(Drv)-1].status) /*состояние контроллера*/ +#define statusSEW1 (sdt->sewdrv[0].status) +#define statusSEW2 (sdt->sewdrv[1].status) +#define statusSEW3 (sdt->sewdrv[2].status) +#define speedSEW(Drv) (sdt->sewdrv[(Drv)-1].set_speed) /*установленная скорость*/ +#define speedSEW1 (sdt->sewdrv[0].set_speed) /* об/мин (rpm)*/ +#define speedSEW2 (sdt->sewdrv[1].set_speed) +#define speedSEW3 (sdt->sewdrv[2].set_speed) +#define vel_SEW(Drv) (sdt->sewdrv[(Drv)-1].mes_speed) /*измеренная скорость */ +#define vel_SEW1 (sdt->sewdrv[0].mes_speed) /* об/мин (rpm)*/ +#define vel_SEW2 (sdt->sewdrv[1].mes_speed) +#define vel_SEW3 (sdt->sewdrv[2].mes_speed) +#define currentSEW(Drv) (sdt->sewdrv[(Drv)-1].current) /*ток (А)*/ +#define currentSEW1 (sdt->sewdrv[0].current) +#define currentSEW2 (sdt->sewdrv[1].current) +#define currentSEW3 (sdt->sewdrv[2].current) +#define indexSEW(Drv) (sdt->sewdrv[(Drv)-1].index) /*номер параметра*/ +#define indexSEW1 (sdt->sewdrv[0].index) +#define indexSEW2 (sdt->sewdrv[1].index) +#define indexSEW3 (sdt->sewdrv[2].index) +#define valueSEW(Drv) (sdt->sewdrv[(Drv)-1].value.l) /*код значения параметра*/ +#define valueSEW1 (sdt->sewdrv[0].value.l) +#define valueSEW2 (sdt->sewdrv[1].value.l) +#define valueSEW3 (sdt->sewdrv[2].value.l) +#define bvalSEW(Drv,Nb) (sdt->sewdrv[(Drv)-1].value.b[Nb]) /*байт кода значения параметра*/ + +/* информация от PEP-контроллеров */ + uint pep_code_a, pep_code_z, pep_code_p; +#define PEP_code_A (sdt->pep_code_a) /* 23р-в дв.кода отсчета A */ +#define PEP_code_Z (sdt->pep_code_z) /* - "" - Z */ +#define PEP_code_P (sdt->pep_code_p) /* - "" - P */ + uint pep_sw_a, pep_sw_z, pep_sw_p; +#define switch_A (sdt->pep_sw_a) /* код концевиков азимута */ +#define Sw_minus_A 1 /* азимут отрицательный (см. code_KOST&0x8000)*/ +#define Sw_plus240_A 2 /* концевик "+240град" */ +#define Sw_minus240_A 4 /* концевик "-240град" */ +#define Sw_minus45_A 8 /* положение "в горизонт" (~-46град)*/ +#define switch_Z (sdt->pep_sw_z) /* код концевиков Z */ +#define Sw_0_Z 0x01 /* концевик "0град" */ +#define Sw_5_Z 0x02 /* концевик "5град" */ +#define Sw_20_Z 0x04 /* концевик "20град" */ +#define Sw_60_Z 0x08 /* концевик "60град" */ +#define Sw_80_Z 0x10 /* концевик "80град" */ +#define Sw_90_Z 0x20 /* концевик "90град" */ +#define switch_P (sdt->pep_sw_p) /* - "" - СПФ */ +#define Sw_No_P 0x00 /* "Нет концевиков" */ +#define Sw_22_P 0x01 /* концевик "22град" */ +#define Sw_89_P 0x02 /* концевик "89град" */ +#define Sw_Sm_P 0x80 /* датчик дыма СПФ */ + uint pep_code_f, pep_code_d, pep_code_ri, pep_code_ro; +#define PEP_code_F (sdt->pep_code_f) /* код отсчета фокуса телескопа */ +#define PEP_code_D (sdt->pep_code_d) /* код отсчета положения купола */ +#define PEP_code_Rin (sdt->pep_code_ri)/* код принятый из РК */ +#define PEP_code_Rout (sdt->pep_code_ro)/* код выдаваемый в РК */ + unsigned char pep_on[10]; /* флаги работы PEP-контроллеров */ +#define PEP_A_On (sdt->pep_on[0]) +#define PEP_A_Off (PEP_A_On==0) +#define PEP_Z_On (sdt->pep_on[1]) +#define PEP_Z_Off (PEP_Z_On==0) +#define PEP_P_On (sdt->pep_on[2]) +#define PEP_P_Off (PEP_P_On==0) +#define PEP_F_On (sdt->pep_on[3]) +#define PEP_F_Off (PEP_F_On==0) +#define PEP_D_On (sdt->pep_on[4]) +#define PEP_D_Off (PEP_D_On==0) +#define PEP_R_On (sdt->pep_on[5]) +#define PEP_R_Off ((PEP_R_On&1)==0) +#define PEP_R_Inp ((PEP_R_On&2)!=0) +#define PEP_K_On (sdt->pep_on[6]) +#define PEP_K_Off ((PEP_K_On&1)==0) +#define PEP_K_Inp ((PEP_K_On&2)!=0) + + /* IERS polar motion (источник: ftp://maia.usno.navy.mil/ser7/ser7.dat) */ + double xpol, ypol; +#define polarX (sdt->xpol) /* X-поправкa полож.полюса */ +#define polarY (sdt->ypol) /* Y-поправкa полож.полюса */ + + double jdate, eetime; +#define JDate (sdt->jdate) /* текущая юлианская дата */ +#define EE_time (sdt->eetime) /* поправ.зв.вр. за "Equation of the Equinoxes" */ + + /* еще ввод метео-данных */ + double val_hmd, inp_hmd; +#define val_Hmd (sdt->val_hmd) /* значение влажности (%) */ +#define inp_Hmd (sdt->val_hmd) /* ручной ввод */ + + /* положение червяка (подвеска) */ + double worm_a, worm_z; +#define worm_A (sdt->worm_a) /* положение подвески A (мкм) */ +#define worm_Z (sdt->worm_z) /* положение подвески Z (мкм) */ + + /* флаги блокировки управления узлами */ + __uint32_t lock_flags; +#define LockFlags (sdt->lock_flags) +#define Lock_A 0x01 +#define Lock_Z 0x02 +#define Lock_P 0x04 +#define Lock_F 0x08 +#define Lock_D 0x10 +#define A_Locked (LockFlags&Lock_A) +#define Z_Locked (LockFlags&Lock_Z) +#define P_Locked (LockFlags&Lock_P) +#define F_Locked (LockFlags&Lock_F) +#define D_Locked (LockFlags&Lock_D) + + /* требуемая скорость привода купола (для упр-я SEW-приводами)*/ + int sew_dome_speed; /* пока тоже что и Dome_State */ +#define Dome_Speed (sdt->sew_dome_speed) /* т.е. D_Lplus,D_Lminus,.... */ + +/* номер SEW-движка купола (для индикации)*/ + int sew_dome_num; +#define DomeSEW_N (sdt->sew_dome_num) + +/* параметры выбранного(DomeSEW_N) SEW-контроллера купола*/ +struct SEWdata sewdomedrv; +#define statusSEWD (sdt->sewdomedrv.status) /*состояние контроллера*/ +#define speedSEWD (sdt->sewdomedrv.set_speed) /*установленная скорость об/мин (rpm)*/ +#define vel_SEWD (sdt->sewdomedrv.mes_speed) /*измеренная скорость об/мин (rpm)*/ +#define currentSEWD (sdt->sewdomedrv.current) /*ток (А)*/ +#define indexSEWD (sdt->sewdomedrv.index) /*номер параметра*/ +#define valueSEWD (sdt->sewdomedrv.value.l) /*код значения параметра*/ + +/* информация PEP-контроллера купола */ + uint pep_code_di, pep_code_do; +#define PEP_code_Din (sdt->pep_code_di) /* код принятый из PEP-купола */ +#define PEP_Dome_SEW_Ok 0x200 +#define PEP_Dome_Cable_Ok 0x100 +#define PEP_code_Dout (sdt->pep_code_do) /* код выдаваемый в PEP-купола */ +#define PEP_Dome_SEW_On 0x10 +#define PEP_Dome_SEW_Off 0x20 + +}; + +#ifndef BTA_MODULE +struct BTA_Data *sdt; +#else +extern struct BTA_Data *sdt; +#endif + +struct BTA_Local { /* структура локальных данных */ + unsigned char reserve[120]; /* свободное место для расширения глобальной области */ + /* (на глобальную область резервируем 1500 байт) */ + double pr_oil_a,pr_oil_z,pr_oil_t; +#define PressOilA (sdtl->pr_oil_a) /* Давление в маслопроводе A (МПа) */ +#define PressOilZ (sdtl->pr_oil_z) /* Давление в маслопроводе Z (МПа) */ +#define PressOilTank (sdtl->pr_oil_t) /* Датчик уровня масла в баке(КПа) */ + double t_oil_1,t_oil_2; +#define OilTemper1 (sdtl->t_oil_1) /* Температура масла */ +#define OilTemper2 (sdtl->t_oil_2) /* Температура охлаждающей воды */ +}; + +#ifndef BTA_MODULE +struct BTA_Local *sdtl; /* конец глобальных, начало локальных данных */ +#else +extern struct BTA_Local *sdtl; +#endif + +#define ClientSide 0 +#define ServerSide 1 + +#ifndef BTA_MODULE +static void bta_data_init(); +static int bta_data_check(); +static void bta_data_close(); + +/* описание блока данных алгоритма управления ("глобальная область") */ +struct SHM_Block sdat = { +{'S','d','a','t',0},sizeof(struct BTA_Data),2048,0444,SHM_RDONLY,bta_data_init,bta_data_check,bta_data_close,0,-1,NULL +}; +#else +extern struct SHM_Block sdat; +#endif + +#ifndef BTA_MODULE +/* инициализация данных алгоритма управления (обнуление "глобальной области") */ +static void bta_data_init() { + int i; + sdt = (struct BTA_Data *)sdat.addr; + sdtl = (struct BTA_Local *)(sdat.addr+sizeof(struct BTA_Data)); + if(sdat.side == ClientSide) { + if(sdt->magic != sdat.key.code) { + fprintf(stderr,"Wrong shared data (maybe server turned off)\n"); + /*exit(1);*/ + } + if(sdt->version == 0) { + fprintf(stderr,"Null shared data version (maybe server turned off)\n"); + /*exit(1);*/ + } + else if(sdt->version != BTA_Data_Ver) { + fprintf(stderr,"Wrong shared data version: I'am - %d, but server - %d ...\n", + BTA_Data_Ver, sdt->version ); + /*exit(1);*/ + } + if(sdt->size != sdat.size) { + if(sdt->size > sdat.size) { + /* но клиент имеет право использовать начальную часть данных */ + fprintf(stderr,"Wrong shared area size: I needs - %d, but server - %d ...\n", + sdat.size, sdt->size ); + } else { + /* "залезание" в пустую резервную часть теперь тоже */ + /* будем оставлять на совести автора клиента! */ + fprintf(stderr,"Attention! Too little shared data structure!\n"); + sleep(1); + fprintf(stderr,"I needs - %d, but server gives only %d ...\n", + sdat.size, sdt->size ); + sleep(1); + fprintf(stderr,"May be server's version too old!?\n"); + /* exit(1); */ + + } + } + return; + } + /* ServerSide */ + if(sdt->magic != sdat.key.code || + sdt->version != BTA_Data_Ver || + sdt->size != sdat.size) { + + for(i=0; imagic = sdat.key.code; + sdt->version = BTA_Data_Ver; + sdt->size = sdat.size; + ServPID = 0; + UseModel = NoModel; + ClockType = Ch7_15; + Sys_Mode = SysStop; + Sys_Target = TagPosition; + Tel_Focus = Prime; + Tel_Hardware = Hard_On; + Tel_Mode = Automatic; + Az_Mode = Rev_Off; + P2_State = P2_Mode = P2_Off; + Foc_State = Foc_Off; + Dome_State = D_Off; + Pos_Corr = PC_On; + TrkOk_Mode = UseDiffVel | UseDiffAZ ; + InpAlpha=InpDelta= 0.; + SrcAlpha=SrcDelta= 0.; + VelAlpha=VelDelta= 0.; + CurAlpha=CurDelta= 0.; + InpAzim=InpZdist = 0.; + Diff_A=Diff_Z=Diff_P=0.0; + pos_cor_A=pos_cor_Z=refract_Z = 0.; + tel_cor_A=tel_cor_Z=tel_ref_Z = 0.; + vel_objA=vel_objZ=vel_objP = 0.; + diff_vA=diff_vZ=diff_vP=0.; + speedA = speedZ = speedP = 0.; + req_speedA = req_speedZ = req_speedP = 0.; + mod_vel_A=mod_vel_Z=mod_vel_P=mod_vel_F=mod_vel_D=0.; + code_KOST = 0; + M_time = S_time = L_time = 0.; + ppndd_A=ppndd_Z=ppndd_P=ppndd_B=0; + dup_A=dup_Z=dup_P=dup_F=dup_D=0; + low_A=low_Z=low_P=low_F=low_D=0; + code_A=code_Z=code_P=code_B=code_F=code_D=code_T1=code_T2=code_T3=code_Wnd=0; + val_A=val_Z=val_P=val_B=val_F=val_D=val_T1=val_T2=val_T3=val_Wnd=val_Alp=val_Del=0.; + vel_A=vel_Z=vel_P=vel_F=vel_D=0.; + for(i=0; imagic == sdat.key.code) && (sdt->version == BTA_Data_Ver) ); +} +static void bta_data_close() { + if(sdat.side == ServerSide) { + sdt->magic = 0; + sdt->version = 0; + } +} + +/* блок информационных сообщений ??? */ +/*struct SHM_Block info = {{'I','n','f','o',0},1024,1024,0444,SHM_RDONLY,NULL,NULL,NULL,0,-1,NULL};*/ + +/* Allocate shared memory segment */ +static void get_shm_block( struct SHM_Block *sb, int server) { + int getsize = (server)? sb->maxsize : sb->size; + + /* first try to find existing one */ + sb->id = shmget(sb->key.code, getsize, sb->mode); + + if (sb->id<0 && errno==ENOENT && server) { + /* if no - try to create a new one */ + int cresize = sb->maxsize; + if(sb->size > cresize) { + fprintf(stderr,"Wrong shm maxsize(%d) < realsize(%d)\n",sb->maxsize,sb->size); + cresize = sb->size; + } + sb->id = shmget(sb->key.code, cresize, IPC_CREAT|IPC_EXCL|sb->mode); + } + if (sb->id<0) { + char msg[80]; + if(server) + sprintf(msg,"Can't create shared memory segment '%s'",sb->key.name); + else + sprintf(msg,"Can't find shared segment '%s' (maybe no server process) ",sb->key.name); + perror(msg); + exit(errno); + } + /* attach it to our memory space */ + sb->addr = (unsigned char *)shmat ( sb->id, NULL, sb->atflag ); + + if ((int)(sb->addr) == -1) { + char msg[80]; + sprintf(msg,"Can't attach shared memory segment '%s'",sb->key.name); + perror(msg); + exit(errno); + } + if(server) { + if((shmctl(sb->id, SHM_LOCK, NULL) < 0) < 0) { + char msg[80]; + sprintf(msg,"Can't prevents swapping of shared memory segment '%s'",sb->key.name); + perror(msg); + exit(errno); + } + } + fprintf(stderr,"Create&attach shared memory segment '%s' %dbytes at %x \n", + sb->key.name, sb->size, (uint)sb->addr); + + sb->side = server; + + if(sb->init!=NULL) + sb->init(); +} +static int close_shm_block( struct SHM_Block *sb) { + int ret; + if(sb->close != NULL) + sb->close(); + if(sb->side == ServerSide) { +// ret = shmctl(sb->id, SHM_UNLOCK, NULL); + ret = shmctl(sb->id, IPC_RMID, NULL); + } + ret = shmdt (sb->addr); + return(ret); +} +#endif + +static int check_shm_block( struct SHM_Block *sb) { + if(sb->check != NULL) + return(sb->check()); + else return(1); +} + +#ifndef BTA_MODULE +int snd_id=-1; /* текущий (и единственный?) канал отсылки команд клиента */ +int cmd_src_pid=0; /* номер процесса источника для ОДНОЙ след.команды */ +__uint32_t cmd_src_ip=0; /* IP-адр. источника для ОДНОЙ след.команды */ +#else +extern int snd_id; +extern int cmd_src_pid; +extern __uint32_t cmd_src_ip; +#endif + +#ifndef BTA_MODULE +/* Create|Find command queue */ +static void get_cmd_queue( struct CMD_Queue *cq, int server) { + if (!server && cq->id>=0) { /* if already in use */ + snd_id = cq->id; /* set current... */ + return; + } + /* first try to find existing one */ + cq->id = msgget(cq->key.code, cq->mode); + if (cq->id<0 && errno==ENOENT && server) + /* if no - try to create a new one */ + cq->id = msgget(cq->key.code, IPC_CREAT|IPC_EXCL|cq->mode); + if (cq->id<0) { + char msg[80]; + if(server) + sprintf(msg,"Can't create comand queue '%s'",cq->key.name); + else + sprintf(msg,"Can't find comand queue '%s' (maybe no server process) ",cq->key.name); + perror(msg); + exit(errno); + } + cq->side = server; + if (server) { + char buf[120]; /* выбросить все команды из очереди */ + while(msgrcv(cq->id, (struct msgbuf *)buf, 112, 0, IPC_NOWAIT)>0); + } else + snd_id = cq->id; + cq->acckey = 0; +} +#endif + +/* установка ключа доступа в тек. канале */ +static void set_acckey(uint newkey) { + if (snd_id<0) return; + if(ucmd.id==snd_id) ucmd.acckey=newkey; + else if(ocmd.id==snd_id) ocmd.acckey=newkey; + else if(mcmd.id==snd_id) mcmd.acckey=newkey; +} + +/* установка данных источника для ОДНОЙ след.команды */ +/* если не подходят умолчания: IP=0(локальная команда) и PID текущ.процесса */ +static void set_cmd_src(__uint32_t ip, int pid) { + cmd_src_pid = pid; + cmd_src_ip = ip; +} + +/* структура сообщения */ +struct my_msgbuf { + __int32_t mtype; /* type of message */ + __uint32_t acckey; /* ключ доступа клиента */ + __uint32_t src_pid; /* номер процесса источника */ + __uint32_t src_ip; /* IP-адр. источника, =0 - локальная команда */ + char mtext[100]; /* message text */ +}; +/* отсылка команд клиента к серверу */ +static void send_cmd(int cmd_code, char *buf, int size) { + struct my_msgbuf mbuf; + + if (snd_id<0) return; + if (size>100) size=100; + if (cmd_code>0) + mbuf.mtype = cmd_code; + else + return; + if(ucmd.id==snd_id) mbuf.acckey=ucmd.acckey; + else if(ocmd.id==snd_id) mbuf.acckey=ocmd.acckey; + else if(mcmd.id==snd_id) mbuf.acckey=mcmd.acckey; + + mbuf.src_pid = cmd_src_pid? cmd_src_pid : getpid(); + mbuf.src_ip = cmd_src_ip; + cmd_src_pid = cmd_src_ip = 0; + + if(size>0) + memcpy( mbuf.mtext, buf, size); + else { + mbuf.mtext[0] = 0; + size = 1; + } + msgsnd( snd_id, (struct msgbuf *)&mbuf, size+12, IPC_NOWAIT); +} +static void send_cmd_noarg(int cmd_code) { + send_cmd(cmd_code, NULL, 0); +} +static void send_cmd_str(int cmd_code, char *arg) { + send_cmd(cmd_code, arg, strlen(arg)+1); +} +static void send_cmd_i1(int cmd_code, int arg1) { + send_cmd(cmd_code, (char *)&arg1, sizeof(int)); +} +static void send_cmd_i2(int cmd_code, int arg1, int arg2) { + int ibuf[2]; + ibuf[0] = arg1; + ibuf[1] = arg2; + send_cmd(cmd_code, (char *)ibuf, 2*sizeof(int)); +} +static void send_cmd_i3(int cmd_code, int arg1, int arg2, int arg3) { + int ibuf[3]; + ibuf[0] = arg1; + ibuf[1] = arg2; + ibuf[2] = arg3; + send_cmd(cmd_code, (char *)ibuf, 3*sizeof(int)); +} +static void send_cmd_i4(int cmd_code, int arg1, int arg2, int arg3, int arg4) { + int ibuf[4]; + ibuf[0] = arg1; + ibuf[1] = arg2; + ibuf[2] = arg3; + ibuf[3] = arg4; + send_cmd(cmd_code, (char *)ibuf, 4*sizeof(int)); +} +static void send_cmd_d1(int cmd_code, double arg1) { + send_cmd(cmd_code, (char *)&arg1, sizeof(double)); +} +static void send_cmd_d2(int cmd_code, double arg1, double arg2) { + double dbuf[2]; + dbuf[0] = arg1; + dbuf[1] = arg2; + send_cmd(cmd_code, (char *)dbuf, 2*sizeof(double)); +} +static void send_cmd_i1d1(int cmd_code, int arg1, double arg2) { + struct { + int ival; + double dval; + } buf; + buf.ival = arg1; + buf.dval = arg2; + send_cmd(cmd_code, (char *)&buf, sizeof(buf)); +} +static void send_cmd_i2d1(int cmd_code, int arg1, int arg2, double arg3) { + struct { + int ival[2]; + double dval; + } buf; + buf.ival[0] = arg1; + buf.ival[1] = arg2; + buf.dval = arg3; + send_cmd(cmd_code, (char *)&buf, sizeof(buf)); +} +static void send_cmd_i3d1(int cmd_code, int arg1, int arg2, int arg3, double arg4) { + struct { + int ival[3]; + double dval; + } buf; + buf.ival[0] = arg1; + buf.ival[1] = arg2; + buf.ival[2] = arg3; + buf.dval = arg4; + send_cmd(cmd_code, (char *)&buf, sizeof(buf)); +} + +static void encode_lev_passwd(char *passwd, int nlev, uint *keylev, uint *codlev) { + char salt[4]; + char *encr; + union { + uint ui; + char c[4]; + } key,cod; + sprintf(salt,"L%1d",nlev); + encr = (char *)crypt(passwd, salt); + cod.c[0] = encr[2]; + key.c[0] = encr[3]; + cod.c[1] = encr[4]; + key.c[1] = encr[5]; + cod.c[2] = encr[6]; + key.c[2] = encr[7]; + cod.c[3] = encr[8]; + key.c[3] = encr[9]; + *keylev = key.ui; + *codlev = cod.ui; +} + +static int find_lev_passwd(char *passwd, uint *keylev, uint *codlev) { + int nlev; + for(nlev=5; nlev>0; nlev--) { + encode_lev_passwd(passwd, nlev, keylev, codlev); + if(nlev == 1 && code_Lev1 == *codlev) break; + if(nlev == 2 && code_Lev2 == *codlev) break; + if(nlev == 3 && code_Lev3 == *codlev) break; + if(nlev == 4 && code_Lev4 == *codlev) break; + if(nlev == 5 && code_Lev5 == *codlev) break; + } + return(nlev); +} + +static int check_lev_passwd(char *passwd) { + uint keylev,codlev; + int nlev; + nlev = find_lev_passwd(passwd, &keylev, &codlev); + if(nlev>0) set_acckey(keylev); + return(nlev); +} + +#pragma GCC diagnostic pop + +#endif // __BTA_SHDATA_H__ diff --git a/extern/fliusb-1.3.tgz b/extern/fliusb-1.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..0c6b727ada7aad6ef847df98751e83558598879d GIT binary patch literal 8719 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 tTwROZgUF)6W2)001RYP7?qC literal 0 HcmV?d00001 diff --git a/extern/libfli-1.104.tgz b/extern/libfli-1.104.tgz new file mode 100644 index 0000000000000000000000000000000000000000..7c9c389bf9851d52b16f8c8a4c1030101f962a65 GIT binary patch literal 89491 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 literal 0 HcmV?d00001 diff --git a/locale/ru/LC_MESSAGES/takepic.mo b/locale/ru/LC_MESSAGES/takepic.mo new file mode 100644 index 0000000000000000000000000000000000000000..af6abc7914f1cabd914318907ed1f7e4a0522e46 GIT binary patch literal 5389 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, YEAR. +# +msgid "" +msgstr "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" + "POT-Creation-Date: 2011-06-28 09:54+0400\n" + "PO-Revision-Date: 2011-06-28 09:22+0300\n" + "Last-Translator: Edward V. Emelianov \n" + "Language-Team: LANGUAGE \n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=koi8-r\n" + "Content-Transfer-Encoding: 8bit\n" + +#. "\tОпции:\n" +#: usage.c:78 +#, c-format +msgid "\tOptions:\n" +msgstr "\tОпции:\n" + +#. %.3f секунд до окончания экспозиции\n +#: takepic.c:166 +#, c-format +msgid "%.3f seconds till exposition ends\n" +msgstr "%.3f секунд до окончания экспозиции\n" + +#. %d секунд до окончания паузы\n +#: takepic.c:220 +#, c-format +msgid "%d seconds till pause ends\n" +msgstr "%d секунд до окончания паузы\n" + +#. Поле изображения: (%ld, %ld)(%ld, %ld) +#: takepic.c:125 +#, c-format +msgid "Array field: (%ld, %ld)(%ld, %ld)" +msgstr "Поле изображения: (%ld, %ld)(%ld, %ld)" + +#. Начинаю экспозицию %dмс, время: %s, файл: %s.%d.%d\n +#: takepic.c:160 +#, c-format +msgid "Begin exposition %dms, exptime: %s, filename: %s.%d.%d\n" +msgstr "Начинаю экспозицию %dмс, время: %s, файл: %s.%d.%d\n" + +#. Камера '%s' из домена %s +#: takepic.c:101 +#, c-format +msgid "Camera '%s', domain %s" +msgstr "Камера '%s' из домена %s" + +#. Не могу открыть файл журнала статистики +#: takepic.c:89 +msgid "Can't open statistics log file" +msgstr "Не могу открыть журнал статистики" + +#. Не могу открыть файл журнала температур +#: takepic.c:80 +msgid "Can't open temperature log file" +msgstr "Не могу открыть журнал температур" + +#. Не могу сохранить файл +#: takepic.c:199 +msgid "Can't save file" +msgstr "Не могу сохранить файл" + +#. Захват кадра %d\n +#: takepic.c:155 +#, c-format +msgid "Capture frame %d\n" +msgstr "Захват кадра %d\n" + +#. "Съемка темновых" +#: usage.c:193 +msgid "Dark frames" +msgstr "Съемка темновых" + +#. "Время экспозиции: %dмс" +#: usage.c:296 +#, c-format +msgid "Exposure time: %dms" +msgstr "Время экспозиции: %dмс" + +#. Видимое поле: %s +#: takepic.c:120 +#, c-format +msgid "Field of view: %s" +msgstr "Видимое поле: %s" + +#. Файл записан в '%s' +#: takepic.c:203 +#, c-format +msgid "File saved as '%s'" +msgstr "Файл записан в '%s'" + +#. Полное журналирование статистики без сохранения изображений +#: usage.c:225 +msgid "Full statistics logging without saving images" +msgstr "Полное журналирование статистики без сохранения изображений" + +#. Апп. версия: %ld +#: takepic.c:110 +#, c-format +msgid "HW revision: %ld" +msgstr "Апп. версия: %ld" + +#. "Гор. биннинг: %d" +#: usage.c:209 +#, c-format +msgid "Horisontal binning: %d" +msgstr "Гор. биннинг: %d" + +#. "Игнорирую аргумент[ы]:\n" +#: usage.c:327 +#, c-format +msgid "Ignore argument[s]:\n" +msgstr "Игнорирую аргумент[ы]:\n" + +#. Статистика по изображению\n +#: takepic.c:470 +#, c-format +msgid "Image stat:\n" +msgstr "Статистика по изображению\n" + +#. "Тип изображения - %s" +#: usage.c:214 +#, c-format +msgid "Image type - %s" +msgstr "Тип изображения - %s" + +#. Температура (внутр.): %f +#: takepic.c:141 +#, c-format +msgid "Inner temperature: %f" +msgstr "Температура (внутр.): %f" + +#. "Название прибора - %s" +#: usage.c:219 +#, c-format +msgid "Instrument name - %s" +msgstr "Название прибора - %s" + +#. Версия библиотеки '%s' +#: takepic.c:75 +#, c-format +msgid "Library version '%s'" +msgstr "Версия библиотеки '%s'" + +#. Модель:\t\t%s +#: takepic.c:106 +#, c-format +msgid "Model:\t\t%s" +msgstr "Модель:\t\t%s" + +#. "N сбросов перед экспозицией" +#: usage.c:87 +msgid "N flushes before exposing" +msgstr "N сбросов перед экспозицией" + +#. Камеры не найдены!\n +#: takepic.c:286 +msgid "No cameras found!\n" +msgstr "Камеры не найдены!\n" + +#. "Имя объекта - %s" +#: usage.c:243 +#, c-format +msgid "Object name - %s" +msgstr "Имя объекта - %s" + +#. "Наблюдатели: %s" +#: usage.c:248 +#, c-format +msgid "Observers: %s" +msgstr "Наблюдатели: %s" + +#. Температура (внешн.): %f +#: takepic.c:144 +#, c-format +msgid "Outern temperature: %f" +msgstr "Температура (внешн.): %f" + +#. "Нет префикса имени выходных файлов" +#: usage.c:316 +msgid "Output file names prefix is absent" +msgstr "Нет префикса имени выходных файлов" + +#. "Пауза: %dс" +#: usage.c:261 +#, c-format +msgid "Pause: %ds" +msgstr "Пауза: %dс" + +#. Размер пикселя: %g x %g +#: takepic.c:116 +#, c-format +msgid "Pixel size: %g x %g" +msgstr "Размер пикселя: %g x %g" + +#. "Автор программы: %s" +#: usage.c:188 +#, c-format +msgid "Program author: %s" +msgstr "Автор программы: %s" + +#. "Название программы: %s" +#: usage.c:253 +#, c-format +msgid "Program name: %s" +msgstr "Название программы: %s" + +#. Считывание изображения: +#: takepic.c:179 +#, c-format +msgid "Read image: " +msgstr "Считывание изображения: " + +#. Прогр. версия: %ld +#: takepic.c:113 +#, c-format +msgid "SW revision: %ld" +msgstr "Прогр. версия: %ld" + +#. "Сохранение журнала температур" +#: usage.c:230 +msgid "Save temperature log" +msgstr "Сохранение журнала температур" + +#. "Серия из %d кадров" +#: usage.c:238 +#, c-format +msgid "Series of %d frames" +msgstr "Серия из %d кадров" + +#. "Установить температуру: %.3f" +#: usage.c:280 +#, c-format +msgid "Set temperature: %.3f" +msgstr "Установить температуру: %.3f" + +#. "Использование:\t%s [опции] <префикс выходных файлов>\n" +#: usage.c:75 +#, c-format +msgid "Usage:\t%s [options] \n" +msgstr "Использование:\t%s [опции] <префикс выходных файлов>\n" + +#. "Верт. биннинг: %d" +#: usage.c:288 +#, c-format +msgid "Vertical binning: %d" +msgstr "Верт. биннинг: %d" + +#. "Неверный" +#: usage.c:206 usage.c:285 +msgid "Wrong" +msgstr "Неверный" + +#. "Неверное время экспозиции: %s" +#: usage.c:293 +#, c-format +msgid "Wrong exposure time: %s" +msgstr "Неверное время экспозиции: %s" + +#. "Неверное кол-во кадров: %s" +#: usage.c:235 +#, c-format +msgid "Wrong frames number in series: %s" +msgstr "Неверное кол-во кадров: %s" + +#. "Неверная нижняя граница: %s" +#: usage.c:54 +#, c-format +msgid "Wrong lower border: %s" +msgstr "Неверная нижняя граница: %s" + +#. "Неверная пауза: %s" +#: usage.c:258 +#, c-format +msgid "Wrong pause length: %s" +msgstr "Неверная пауза: %s" + +#. "Неверное значение температуры: %s (должно быть от -55 до 30)" +#: usage.c:276 +#, c-format +msgid "Wrong temperature: %s (must be from -55 to 30)" +msgstr "Неверное значение температуры: %s (должно быть от -55 до 30)" + +#. "Неверная верхняя граница: %s" +#: usage.c:59 +#, c-format +msgid "Wrong upper border: %s" +msgstr "Неверная верхняя граница: %s" + +#. "Диапазон по X: [%d, %d]" +#: usage.c:301 +#, c-format +msgid "X range: [%d, %d]" +msgstr "Диапазон по X: [%d, %d]" + +#. "Диапазон по Y: [%d, %d]" +#: usage.c:306 +#, c-format +msgid "Y range: [%d, %d]" +msgstr "Диапазон по Y: [%d, %d]" + +#. дата/время +#: takepic.c:171 takepic.c:225 +msgid "date/time" +msgstr "дата/время" + +#. "не сохранять изображения, лишь вести запись статистки" +#: usage.c:99 +msgid "don't save images, only make all-stat log" +msgstr "не сохранять изображения, лишь вести запись статистки" + +#. "биннинг N пикселей по горизонтали" +#: usage.c:90 +msgid "horizontal binning to N pixels" +msgstr "биннинг N пикселей по горизонтали" + +#. "тип изображения" +#: usage.c:93 +msgid "image type" +msgstr "тип изображения" + +#. "название прибора" +#: usage.c:96 +msgid "instrument name" +msgstr "название прибора" + +#. "выдержать ptime секунд между экспозициями" +#: usage.c:117 +msgid "make pause for ptime seconds between expositions" +msgstr "выдержать ptime секунд между экспозициями" + +#. "N кадров в серии" +#: usage.c:105 +msgid "make series of N frames" +msgstr "N кадров в серии" + +#. "вести запись рабочих температур в файл temp_log" +#: usage.c:102 +msgid "make temperatures logging to file temp_log" +msgstr "вести запись рабочих температур в файл temp_log" + +#. "не открывать затвор при экспозиции (\"темновые\")" +#: usage.c:84 +msgid "not open shutter, when exposing (\"dark frames\")" +msgstr "не открывать затвор при экспозиции (\"темновые\")" + +#. "не сохранять изображение, а только отобразить статистику" +#: usage.c:120 +msgid "not save image, just show statistics" +msgstr "не сохранять изображение, а только отобразить статистику" + +#. "название объекта" +#: usage.c:108 +msgid "object name" +msgstr "название объекта" + +#. "имена наблюдателей" +#: usage.c:111 +msgid "observers' names" +msgstr "имена наблюдателей" + +#. "название программы наблюдений" +#: usage.c:114 +msgid "observing program name" +msgstr "название программы наблюдений" + +#. "только задать/получить температуру" +#. "только отобразить/задать температуру" +#: usage.c:123 usage.c:270 +msgid "only set/get temperature" +msgstr "только задать/получить температуру" + +#. "автор программы" +#: usage.c:81 +msgid "program author" +msgstr "автор программы" + +#. "выбрать диапазон для считывания" +#: usage.c:135 usage.c:138 +msgid "select clip region" +msgstr "выбрать диапазон для считывания" + +#. "время экспозиции exptime мс" +#: usage.c:132 +msgid "set exposure time to exptime ms" +msgstr "время экспозиции exptime мс" + +#. "задать рабочую температуру degr градусов" +#: usage.c:126 +msgid "set work temperature to degr C" +msgstr "задать рабочую температуру degr градусов" + +#. "биннинг N пикселей по вертикали" +#: usage.c:129 +msgid "vertical binning to N pixels" +msgstr "биннинг N пикселей по вертикали" diff --git a/takepic.c b/takepic.c new file mode 100644 index 0000000..9748c97 --- /dev/null +++ b/takepic.c @@ -0,0 +1,503 @@ +#include "takepic.h" +#include "usage.h" +#ifdef USE_BTA +#include "bta_print.h" +#endif +#include +#include +#include +#include + +#ifdef USEPNG +int writepng(char *filename, int width, int height, void *data); +#endif /* USEPNG */ + +#define BUFF_SIZ 4096 + +#define TMBUFSIZ 40 // длина буфера для строки с временем +char tm_buf[TMBUFSIZ]; // буфер для строки с временем + +u_int16_t max=0, min=65535; // экстремальные значения текущего изображения +double avr, std; // среднее значение и среднеквадратическое отклонение текущего изобр. +char *camera = NULL, viewfield[80]; +double pixX, pixY; // размер пикселя + +int numcams = 0; + +void print_stat(u_int16_t *img, long size, FILE* f); + +int itime(){ // усл. время в секундах + struct timeval ct; + gettimeofday(&ct, NULL); + return (ct.tv_sec); +} +int time0; +int ltime(){ // время, прошедшее с момента запуска программы + return(itime()-time0); +} + +size_t curtime(char *s_time){ // строка - текущее время/дата + time_t tm = time(NULL); + return strftime(s_time, TMBUFSIZ, "%d/%m/%Y,%H:%M:%S", localtime(&tm)); +} + +double t_ext, t_int; // внешняя т., т. камеры (+ на конец экспозиции) +time_t expStartsAt; // время начала экспозиции (time_t) + +int check_filename(char *buff, char *outfile, char *ext){ + struct stat filestat; + int num; + for(num = 1; num < 10000; num++){ + if(snprintf(buff, BUFF_SIZ, "%s_%04d.%s", outfile, num, ext) < 1) + return 0; + if(stat(buff, &filestat)) // файла не существует + return 1; + } + return 0; +} + +int main(int argc, char **argv){ + int i; // для циклов + FILE *f_tlog = NULL;// файл, в который будет записываться журнал температур + FILE *f_statlog = NULL; // файл для статистики в режиме "только статистика" + char libver[LIBVERSIZ]; // буфер для версии библиотеки fli + cam_t *cam = NULL; // список камер + setlocale(LC_ALL, getenv("LC_ALL")); + setlocale(LC_NUMERIC, "C"); + bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); + //bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); + parse_args(argc, argv); + //TRYFUNC(FLISetDebugLevel, NULL /* "NO HOST" */, FLIDEBUG_ALL); + TRYFUNC(FLISetDebugLevel, NULL, FLIDEBUG_NONE); + TRYFUNC(FLIGetLibVersion, libver, LIBVERSIZ); + // Версия библиотеки '%s' + info(_("Library version '%s'"), libver); + findcams(FLIDOMAIN_USB, &cam); + if(save_Tlog){ + f_tlog = fopen("temp_log", "a"); + // Не могу открыть файл журнала температур + if(!f_tlog) err(1, _("Can't open temperature log file")); + fprintf(f_tlog, "\n\n\n"); + } + if(stat_logging){ + struct stat s; + char print_hdr = 1; + if(stat("stat_log", &s) == 0) print_hdr = 0; + f_statlog = fopen("stat_log", "a"); + // Не могу открыть файл журнала статистики + if(!f_statlog) err(1, _("Can't open statistics log file")); + if(print_hdr) + fprintf(f_statlog, "Time\t\t\tUnix time\tTexp\tTint\tText\tImax\tImin\tIavr\tIstd\tNover\tN>3std\tIavr3\t\tIstd3\n"); + } + i = 0; + for (i = 0; i < numcams; i++){ + long x0,x1, y0,y1, row, img_rows, row_width, ltmp, img_size; + flidev_t dev; + char buff[BUFF_SIZ]; + u_int16_t *img; + int j; + // Камера '%s' из домена %s + info(_("Camera '%s', domain %s"), cam[i].name, cam[i].dname); + TRYFUNC(FLIOpen, &dev, cam[i].name, FLIDEVICE_CAMERA | cam[i].domain); + if(r) continue; + TRYFUNC(FLIGetModel, dev, buff, BUFF_SIZ); + // Модель:\t\t%s + info(_("Model:\t\t%s"), buff); + camera = strdup(buff); + TRYFUNC(FLIGetHWRevision, dev, <mp); + // Апп. версия: %ld + info(_("HW revision: %ld"), ltmp); + TRYFUNC(FLIGetFWRevision, dev, <mp); + // Прогр. версия: %ld + info(_("SW revision: %ld"), ltmp); + TRYFUNC(FLIGetPixelSize, dev, &pixX, &pixY); + // Размер пикселя: %g x %g + info(_("Pixel size: %g x %g"), pixX, pixY); + TRYFUNC(FLIGetVisibleArea, dev, &x0, &y0, &x1, &y1); + snprintf(viewfield, 79, "(%ld, %ld)(%ld, %ld)", x0, y0, x1, y1); + // Видимое поле: %s + info(_("Field of view: %s"), viewfield); + if(X1 > x1) X1 = x1; + if(Y1 > y1) Y1 = y1; + TRYFUNC(FLIGetArrayArea, dev, &x0, &y0, &x1, &y1); + // Поле изображения: (%ld, %ld)(%ld, %ld) + info(_("Array field: (%ld, %ld)(%ld, %ld)"), x0, y0, x1, y1); + TRYFUNC(FLISetHBin, dev, hbin); + TRYFUNC(FLISetVBin, dev, vbin); + if(X0 == -1) X0 = x0; // задаем значения по умолчанию + if(Y0 == -1) Y0 = y0; + if(X1 == -1) X1 = x1; + if(Y1 == -1) Y1 = y1; + row_width = (X1 - X0) / hbin; + img_rows = (Y1 - Y0) / vbin; + //TRYFUNC(FLISetImageArea, dev, ltmp, tmp2, tmp3, tmp4); + TRYFUNC(FLISetImageArea, dev, X0, Y0, + X0 + (X1 - X0) / hbin, Y0 + (Y1 - Y0) / vbin); + TRYFUNC(FLISetNFlushes, dev, flushes); + if(set_T) TRYFUNC(FLISetTemperature, dev, temperature); + TRYFUNC(FLIGetTemperature, dev, &t_int); + // Температура (внутр.): %f + info(_("Inner temperature: %f"), t_int); + TRYFUNC(FLIReadTemperature, dev, FLI_TEMPERATURE_EXTERNAL, &t_ext); + // Температура (внешн.): %f + info(_("Outern temperature: %f"), t_ext); + if(only_T) continue; + TRYFUNC(FLISetExposureTime, dev, exptime); + TRYFUNC(FLISetFrameType, dev, frametype); + //TRYFUNC(FLISetBitDepth, dev, FLI_MODE_16BIT); + img_size = img_rows * row_width * sizeof(u_int16_t); + if((img = malloc(img_size)) == NULL) err(1, "malloc() failed"); + for (j = 0; j < pics; j ++){ + TRYFUNC(FLIGetTemperature, dev, &temperature); // температура до начала экспозиции + printf("\n\n"); + // Захват кадра %d\n + printf(_("Capture frame %d\n"), j); + TRYFUNC(FLIExposeFrame, dev); + expStartsAt = time(NULL); // время начала экспозиции + if(save_Tlog) if(curtime(tm_buf)) + // Начинаю экспозицию %dмс, время: %s, файл: %s.%d.%d\n + fprintf(f_tlog, _("Begin exposition %dms, exptime: %s, filename: %s.%d.%d\n"), + exptime, tm_buf, outfile, i, j); + do{ + TRYFUNC(FLIGetExposureStatus, dev, <mp); + if(r) break; + // %.3f секунд до окончания экспозиции\n + printf(_("%.3f seconds till exposition ends\n"), ((float)ltmp) / 1000.); + TRYFUNC(FLIGetTemperature, dev, &t_int); + TRYFUNC(FLIReadTemperature, dev, FLI_TEMPERATURE_EXTERNAL, &t_ext); + if(curtime(tm_buf)){ + // дата/время + printf("%s: %s\tText=%.2f\tTint=%.2f\n", _("date/time"), tm_buf, t_ext, t_int); + if(save_Tlog) fprintf(f_tlog, "%s\t\t%.5f\t\t%.5f\n", tm_buf, t_ext, t_int); + } + else info("curtime() error"); + if(ltmp > 10000) sleep(10); + else usleep(ltmp * 1000); + }while(ltmp); + // Считывание изображения: + printf(_("Read image: ")); + int portion = 0; + for (row = 0; row < img_rows; row++){ + TRYFUNC(FLIGrabRow, dev, &img[row * row_width], row_width); + if(r) break; + int progress = (int)(((float)row / (float)img_rows) * 100.); + if(progress/5 > portion){ + if((++portion)%2) printf(".."); + else printf("%d%%", portion*5); + fflush(stdout); + } + } + printf("100%%\n"); + curtime(tm_buf); + if(f_statlog) + fprintf(f_statlog, "%s\t%ld\t%g\t%.2f\t%.2f\t", tm_buf, time(NULL), exptime/1000., t_int, t_ext); + print_stat(img, row_width * img_rows, f_statlog); + inline void WRITEIMG(int (*writefn)(char*,int,int,void*), char *ext){ + if(!check_filename(buff, outfile, ext)) + // Не могу сохранить файл + err(1, _("Can't save file")); + else{ + TRYFUNC(writefn, buff, row_width, img_rows, img); + // Файл записан в '%s' + if (r == 0) info(_("File saved as '%s'"), buff); + } + } + if(save_image){ + #ifdef USERAW + WRITEIMG(writeraw, "raw"); + #endif // USERAW + WRITEIMG(writefits, "fit"); + #ifdef USEPNG + WRITEIMG(writepng, "png"); + #endif /* USEPNG */ + } + if(pause_len){ + int delta; + time0 = itime(); + while((delta = pause_len - ltime()) > 0){ + // %d секунд до окончания паузы\n + printf(_("%d seconds till pause ends\n"), delta); + TRYFUNC(FLIGetTemperature, dev, &t_int); + TRYFUNC(FLIReadTemperature, dev, FLI_TEMPERATURE_EXTERNAL, &t_ext); + if(curtime(tm_buf)){ + // дата/время + printf("%s: %s\tText=%.2f\tTint=%.2f\n", _("date/time"), tm_buf, t_ext, t_int); + if(save_Tlog) fprintf(f_tlog, "%s\t\t%.5f\t\t%.5f\n", tm_buf, t_ext, t_int); + } + else info("curtime() error"); + if(delta > 10) sleep(10); + else sleep(delta); + } + } + } + free(camera); + free(img); + TRYFUNC(FLIClose, dev); + } + for (i = 0; i < numcams; i++) + free(cam[i].name); + free(cam); + if(f_tlog) fclose(f_tlog); + if(f_statlog) fclose(f_statlog); + exit(0); +} + +void findcams(flidomain_t domain, cam_t **cam){ + long r; + char **tmplist; + TRYFUNC(FLIList, domain | FLIDEVICE_CAMERA, &tmplist); + if (tmplist != NULL && tmplist[0] != NULL){ + int i, cams = 0; + for (i = 0; tmplist[i] != NULL; i++) cams++; + if ((*cam = realloc(*cam, (numcams + cams) * sizeof(cam_t))) == NULL) + err(1, "realloc() failed"); + for (i = 0; tmplist[i] != NULL; i++) { + int j; + cam_t *tmpcam = *cam + i; + for (j = 0; tmplist[i][j] != '\0'; j++) + if (tmplist[i][j] == ';'){ + tmplist[i][j] = '\0'; + break; + } + tmpcam->domain = domain; + switch (domain){ + case FLIDOMAIN_PARALLEL_PORT: + tmpcam->dname = "parallel port"; + break; + case FLIDOMAIN_USB: + tmpcam->dname = "USB"; + break; + case FLIDOMAIN_SERIAL: + tmpcam->dname = "serial"; + break; + case FLIDOMAIN_INET: + tmpcam->dname = "inet"; + break; + default: + tmpcam->dname = "Unknown domain"; + break; + } + tmpcam->name = strdup(tmplist[i]); + } + numcams += cams; + } + // Камеры не найдены!\n + else info(_("No cameras found!\n")); + TRYFUNC(FLIFreeList, tmplist); + return; +} + +#ifdef USERAW +int writeraw(char *filename, int width, int height, void *data){ + int fd, size, err; + if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) == -1){ + warn("open(%s) failed", filename); + return -errno; + } + size = width * height * sizeof(u_int16_t); + if ((err = write(fd, data, size)) != size){ + warn("write() failed"); + err = -errno; + } + else err = 0; + close(fd); + return err; +} +#endif // USERAW + +/* + * В шапке должны быть: + * RATE / Readout rate (KPix/sec) + * GAIN / gain, e/ADU + * SEEING / Seeing ('') + * IMSCALE / Image scale (''/pix x ''/pix) + * CLOUDS / Clouds (%) + */ + + +int writefits(char *filename, int width, int height, void *data){ + long naxes[2] = {width, height}, startTime; + double tmp = 0.0; + struct tm *tm_starttime; + char buf[80]; + time_t savetime = time(NULL); + fitsfile *fp; + 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"); + // 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"); + // DETECTOR / detector + if(camera){ + WRITEKEY(fp, TSTRING, "DETECTOR", camera, "Detector model"); + } + // INSTRUME / Instrument + if(instrument){ + WRITEKEY(fp, TSTRING, "INSTRUME", instrument, "Instrument"); + }else + WRITEKEY(fp, TSTRING, "INSTRUME", "direct imaging", "Instrument"); + // BZERO / zero point in scaling equation + //WRITEKEY(fp, TDOUBLE, "BZERO", &tmp, "zero point in scaling equation"); + // BSCALE / linear factor in scaling equation + //tmp = 1.0; WRITEKEY(fp, TDOUBLE, "BSCALE", &tmp, "linear factor in scaling equation"); + snprintf(buf, 79, "%.g x %.g", pixX, pixY); + // PXSIZE / pixel size + WRITEKEY(fp, TSTRING, "PXSIZE", buf, "Pixel size in m"); + 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"); + if(exptime == 0) sprintf(buf, "bias"); + else if(frametype == FLI_FRAME_TYPE_DARK) 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"); + // DATAMAX, DATAMIN / Max,min pixel value + WRITEKEY(fp, TUSHORT, "DATAMAX", &max, "Max pixel value"); + WRITEKEY(fp, TUSHORT, "DATAMIN", &min, "Min pixel value"); + WRITEKEY(fp, TDOUBLE, "DATAAVR", &avr, "Average pixel value"); + WRITEKEY(fp, TDOUBLE, "DATASTD", &std, "Standart deviation of pixel value"); + 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(fp, 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)"); + tmp = (double)exptime / 1000.; + // EXPTIME / actual exposition time (sec) + WRITEKEY(fp, 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)"); + startTime = (long)expStartsAt; + tm_starttime = localtime(&expStartsAt); + strftime(buf, 79, "exposition starts at %d/%m/%Y, %H:%M:%S (local)", tm_starttime); + WRITEKEY(fp, TLONG, "UNIXTIME", &startTime, buf); + strftime(buf, 79, "%Y/%m/%d", tm_starttime); + // DATE-OBS / DATE (YYYY/MM/DD) OF OBS. + WRITEKEY(fp, TSTRING, "DATE-OBS", buf, "DATE OF OBS. (YYYY/MM/DD, local)"); + strftime(buf, 79, "%H:%M:%S", tm_starttime); + // START / Measurement start time (local) (hh:mm:ss) + WRITEKEY(fp, TSTRING, "START", buf, "Measurement start time (hh:mm:ss, local)"); + // OBJECT / Object name + if(objname){ + WRITEKEY(fp, 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)"); + } + // OBSERVER / Observers + if(observers){ + WRITEKEY(fp, TSTRING, "OBSERVER", observers, "Observers"); + } + // PROG-ID / Observation program identifier + if(prog_id){ + WRITEKEY(fp, TSTRING, "PROG-ID", prog_id, "Observation program identifier"); + } + // AUTHOR / Author of the program + if(author){ + WRITEKEY(fp, TSTRING, "AUTHOR", author, "Author of the program"); + } +#ifdef USE_BTA + write_bta_data(fp); +#endif + TRYFITS(fits_write_img, fp, TUSHORT, 1, width * height, data); + TRYFITS(fits_close_file, fp); + return 0; +} + +#ifdef USEPNG +int writepng(char *filename, int width, int height, void *data){ + int err; + FILE *fp = NULL; + png_structp pngptr = NULL; + png_infop infoptr = NULL; + void *row; + if ((fp = fopen(filename, "wb")) == NULL){ + err = -errno; + goto done; + } + if ((pngptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL)) == NULL){ + err = -ENOMEM; + goto done; + } + if ((infoptr = png_create_info_struct(pngptr)) == NULL){ + err = -ENOMEM; + goto done; + } + png_init_io(pngptr, fp); + png_set_compression_level(pngptr, Z_BEST_COMPRESSION); + png_set_IHDR(pngptr, infoptr, width, height, 16, PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info(pngptr, infoptr); + png_set_swap(pngptr); + for(row = data; height > 0; row += width * sizeof(u_int16_t), height--) + png_write_row(pngptr, row); + png_write_end(pngptr, infoptr); + err = 0; + done: + if(fp) fclose(fp); + if(pngptr) png_destroy_write_struct(&pngptr, &infoptr); + return err; +} +#endif /* USEPNG */ + +void print_stat(u_int16_t *img, long size, FILE *f){ + long i, Noverld = 0L, N = 0L; + double pv, sum=0., sum2=0., sz = (double)size, tres; + u_int16_t *ptr = img, val; + max = 0; min = 65535; + for(i = 0; i < size; i++, ptr++){ + val = *ptr; + pv = (double) val; + sum += pv; + sum2 += (pv * pv); + if(max < val) max = val; + if(min > val) min = val; + if(val >= 65530) Noverld++; + } + // Статистика по изображению\n + printf(_("Image stat:\n")); + avr = sum/sz; + printf("avr = %.1f, std = %.1f, Noverload = %ld\n", avr, + std = sqrt(fabs(sum2/sz - avr*avr)), Noverld); + printf("max = %u, min = %u, size = %ld\n", max, min, size); + // полная статистика, если у нас режим сохранения статистики: + if(!f) return; + // Iсреднее, Iсигма, Nперекоп + fprintf(f, "%d\t%d\t%.3f\t%.3f\t%ld\t", max, min, avr, std, Noverld); + Noverld = 0L; + ptr = img; sum = 0.; sum2 = 0.; + tres = avr + 3. * std; // порог по максимуму - 3 сигмы + for(i = 0; i < size; i++, ptr++){ + val = *ptr; + pv = (double) val; + if(pv > tres){ + Noverld++; // теперь это - кол-во слишком ярких пикселей + continue; + } + sum += pv; + sum2 += (pv * pv); + N++; + } + if(N == 0L){ + fprintf(f, "err\n"); + return; + } + sz = (double)N; + avr = sum/sz; std = sqrt(fabs(sum2/sz - avr*avr)); + // Nбольше3сигм, Iсреднее в пределах 3сигм, Iсигма в пределах 3сигм + fprintf(f, "%ld\t%.3f\t%.3f\n", Noverld, avr, std); + fflush(f); + printf("Novr3 = %ld\n", Noverld); +} diff --git a/takepic.h b/takepic.h new file mode 100644 index 0000000..189f881 --- /dev/null +++ b/takepic.h @@ -0,0 +1,95 @@ +#ifndef __TAKEPIC_H__ +#define __TAKEPIC_H__ +#define _XOPEN_SOURCE 501 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USEPNG +#include +#endif /* USEPNG */ + +#include "libfli.h" + +#ifndef GETTEXT_PACKAGE +#define GETTEXT_PACKAGE "takepic" +#endif +#ifndef LOCALEDIR +#define LOCALEDIR "./locale" +#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) +#else + #define FNAME() do{}while(0) + #define DBG(...) do{}while(0) +#endif //EBUG + +extern const char *__progname; +#define info(format, args...) do{ \ + printf("%s: ", __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) + +#define LIBVERSIZ 1024 + +typedef struct{ + flidomain_t domain; + char *dname; + char *name; +}cam_t; + +void findcams(flidomain_t domain, cam_t **cam); +#ifdef USERAW +int writeraw(char *filename, int width, int height, void *data); +#endif // USERAW + +#define TRYFITS(f, ...) \ +do{ int status = 0; \ + f(__VA_ARGS__, &status); \ + if (status){ \ + fits_report_error(stderr, status); \ + return -1;} \ +}while(0) +#define WRITEKEY(...) \ +do{ int status = 0; \ + fits_write_key(__VA_ARGS__, &status); \ + if(status) fits_report_error(stderr, status);\ +}while(0) +int writefits(char *filename, int width, int height, void *data); + + +#endif // __TAKEPIC_H__ diff --git a/usage.c b/usage.c new file mode 100644 index 0000000..1cc7200 --- /dev/null +++ b/usage.c @@ -0,0 +1,331 @@ +#include "usage.h" + +char + *objname = NULL // имя объекта + ,*outfile = NULL // префикс имени файла для записи raw/fits + ,*objtype = NULL // тип кадра (по умолчанию - object, при -d - dark) + ,*instrument = NULL // название прибора (по умолчанию - "direct imaging") + ,*observers = NULL // наблюдатели + ,*prog_id = NULL // имя программы + ,*author = NULL // автор +; +int + exptime = 500 // время экспозиции (в мс) + ,pics = 1 // кол-во снимаемых кадров + ,hbin = 1 // горизонтальный биннинг + ,vbin = 1 // вертикальный биннинг + ,X0=-1,Y0=-1 // координаты верхнего левого угла считываемого изображения + // -1 - вся область, в т.ч. "оверскан" + ,X1=-1,Y1=-1 // координаты правого нижнего угла считываемого изображения + ,flushes = 1 // кол-во сбросов + ,pause_len = 0 // продолжительность паузы (в с) между кадрами +; +double temperature = -20.; // температура (которую задать, потом - на начало эксп.) + +fliframe_t frametype = FLI_FRAME_TYPE_NORMAL; // тип фрейма (обычный или темновой) + +bool + only_T = FALSE // только отобразить температуру - и выйти + ,set_T = FALSE // задать нужную температуру + ,save_Tlog = FALSE // сохранять журнал температур + ,save_image = TRUE // сохранять изображение + ,stat_logging = FALSE // полное логгирование статистики +; +int myatoi(int *num, const char *str){ // "аккуратный" atoi + long tmp; + char *endptr; + tmp = strtol(str, &endptr, 0); + if (*str == '\0' || *endptr != '\0' || tmp < INT_MIN || tmp > INT_MAX){ + return -1; + } + *num = (int)tmp; + return 0; +} + +void getrange(int *X0, int *X1, char *arg){ + char *a = NULL, *pair; + pair = strdup(arg); + if((a = strchr(pair, ','))){ + *a = 0; + a++; + } + if(myatoi(X0, pair) || *X0 < 0){ + // "Неверная нижняя граница: %s" + usage(_("Wrong lower border: %s"), pair); + } + if(a){ + if(myatoi(X1, a) || *X1 < 0 || *X1 <= *X0){ + // "Неверная верхняя граница: %s" + usage(_("Wrong upper border: %s"), pair); + } + } + free(pair); +} + +void usage(char *fmt, ...){ + va_list ap; + va_start(ap, fmt); + printf("\n"); + if (fmt != NULL){ + vprintf(fmt, ap); + printf("\n\n"); + } + va_end(ap); + // "Использование:\t%s [опции] <префикс выходных файлов>\n" + printf(_("Usage:\t%s [options] \n"), + __progname); + // "\tОпции:\n" + printf(_("\tOptions:\n")); + printf("\t-A,\t--author=author\t\t%s\n", + // "автор программы" + _("program author")); + printf("\t-d,\t--dark\t\t\t%s\n", + // "не открывать затвор при экспозиции (\"темновые\")" + _("not open shutter, when exposing (\"dark frames\")")); + printf("\t-f,\t--flushes=N\t\t%s\n", + // "N сбросов перед экспозицией" + _("N flushes before exposing")); + printf("\t-h,\t--hbin=N\t\t%s\n", + // "биннинг N пикселей по горизонтали" + _("horizontal binning to N pixels")); + printf("\t-I,\t--image-type=type\t%s\n", + // "тип изображения" + _("image type")); + printf("\t-i,\t--instrument=instr\t%s\n", + // "название прибора" + _("instrument name")); + printf("\t-L,\t--log-only\t\t%s\n", + // "не сохранять изображения, лишь вести запись статистки" + _("don't save images, only make all-stat log")); + printf("\t-l,\t--tlog\t\t\t%s\n", + // "вести запись рабочих температур в файл temp_log" + _("make temperatures logging to file temp_log")); + printf("\t-n,\t--nframes=N\t\t%s\n", + // "N кадров в серии" + _("make series of N frames")); + printf("\t-O,\t--object=obj\t\t%s\n", + // "название объекта" + _("object name")); + printf("\t-o,\t--observer=obs\t\t%s\n", + // "имена наблюдателей" + _("observers' names")); + printf("\t-P,\t--prog-id=prname\t%s\n", + // "название программы наблюдений" + _("observing program name")); + printf("\t-p,\t--pause-len=ptime\t%s\n", + // "выдержать ptime секунд между экспозициями" + _("make pause for ptime seconds between expositions")); + printf("\t-s,\t--only-stat\t\t%s\n", + // "не сохранять изображение, а только отобразить статистику" + _("not save image, just show statistics")); + printf("\t-T,\t--only-temp\t\t%s\n", + // "только задать/получить температуру" + _("only set/get temperature")); + printf("\t-t,\t--set-temp=degr\t\t%s\n", + // "задать рабочую температуру degr градусов" + _("set work temperature to degr C")); + printf("\t-v,\t--vbin=N\t\t%s\n", + // "биннинг N пикселей по вертикали" + _("vertical binning to N pixels")); + printf("\t-x,\t--exp=exptime\t\t%s\n", + // "время экспозиции exptime мс" + _("set exposure time to exptime ms")); + printf("\t-X,\t--xclip=X0[,X1]\t\t%s [X0:X1]\n", + // "выбрать диапазон для считывания" + _("select clip region")); + printf("\t-Y,\t--xclip=Y0[,Y1]\t\t%s [Y0:Y1]\n", + // "выбрать диапазон для считывания" + _("select clip region")); + exit(0); +} + +void parse_args(int argc, char **argv){ + int i; + char short_options[] = "A:df:h:I:i:Lln:O:o:P:p:sTt:v:x:X:Y:"; + struct option long_options[] = { +/* { name, has_arg, flag, val }, где: + * name - имя "длинного" параметра + * has_arg = 0 - нет аргумента, 1 - обязательный аргумент, 2 - необязательный аргумент + * flag = NULL для возврата val, указатель на переменную int - для присвоения ей + * значения val (в этом случае функция возвращает 0) + * val - возвращаемое значение getopt_long или значение, присваемое указателю flag + * !!! последняя строка - четыре нуля + */ + {"author", 1, 0, 'A'}, + {"dark", 0, 0, 'd'}, + {"flushes", 1, 0, 'f'}, + {"hbin", 1, 0, 'h'}, + {"image-type", 1, 0, 'I'}, + {"instrument", 1, 0, 'i'}, + {"log-only", 0, 0, 'L'}, + {"tlog", 0, 0, 'l'}, + {"nframes", 1, 0, 'n'}, + {"object", 1, 0, 'O'}, + {"observers", 1, 0, 'o'}, + {"prog-id", 1, 0, 'P'}, + {"pause-len", 1, 0, 'p'}, + {"only-stat", 0, 0, 's'}, + {"only-temp", 0, 0, 'T'}, + {"set-temp", 1, 0, 't'}, + {"vbin", 1, 0, 'v'}, + {"exp", 1, 0, 'x'}, + {"xclip", 1, 0, 'X'}, + {"yclip", 1, 0, 'Y'}, + { 0, 0, 0, 0 } + }; +/* "длинные" и "короткие" параметры getopt_long не должны совпадать + * (лишь если "длинный" должен значить то же, что "короткий", для него + * должно быть flag = NULL, val = значение короткого + */ + while (1){ + int opt; + if((opt = getopt_long(argc, argv, short_options, + long_options, NULL)) == -1) break; + switch(opt){ + case 'A': + author = strdup(optarg); + // "Автор программы: %s" + info(_("Program author: %s"), author); + break; + case 'd': + frametype = FLI_FRAME_TYPE_DARK; + // "Съемка темновых" + info(_("Dark frames")); + break; + case 'f': + if (myatoi(&flushes, optarg) || flushes < 0){ + // "Неверное кол-во сбросов: %s" + usage("Wrong flushes number: %s", optarg); + } + // "Кол-во сбросов: %d" + info("Flushes number: %d", flushes); + break; + case 'h': + if (myatoi(&hbin, optarg) || hbin < 1 || hbin > 16){ + // "Неверный" + usage("%s hbin: %s", _("Wrong"), optarg); + } + // "Гор. биннинг: %d" + info(_("Horisontal binning: %d"), hbin); + break; + case 'I': + objtype = strdup(optarg); + // "Тип изображения - %s" + info(_("Image type - %s"), objtype); + break; + case 'i': + instrument = strdup(optarg); + // "Название прибора - %s" + info(_("Instrument name - %s"), instrument); + break; + case 'L': + stat_logging = TRUE; + save_image = FALSE; + // Полное журналирование статистики без сохранения изображений + info(_("Full statistics logging without saving images")); + break; + case 'l': + save_Tlog = TRUE; + // "Сохранение журнала температур" + info(_("Save temperature log")); + break; + case 'n': + if (myatoi(&pics, optarg) || pics <= 0){ + // "Неверное кол-во кадров: %s" + usage(_("Wrong frames number in series: %s"), optarg); + } + // "Серия из %d кадров" + info(_("Series of %d frames"), pics); + break; + case 'O': + objname = strdup(optarg); + // "Имя объекта - %s" + info(_("Object name - %s"), objname); + break; + case 'o': + observers = strdup(optarg); + // "Наблюдатели: %s" + info(_("Observers: %s"), observers); + break; + case 'P': + prog_id = strdup(optarg); + // "Название программы: %s" + info(_("Program name: %s"), prog_id); + break; + case 'p': + if (myatoi(&pause_len, optarg) || pause_len < 0){ + // "Неверная пауза: %s" + usage(_("Wrong pause length: %s"), optarg); + } + // "Пауза: %dс" + info(_("Pause: %ds"), pause_len); + break; + case 's': + save_image = FALSE; + break; + case 'T': + only_T = TRUE; + save_image = FALSE; + // "только отобразить/задать температуру" + info(_("only set/get temperature")); + break; + case 't': + temperature = atof(optarg); + if(temperature < -55. || temperature > 30.){ + // "Неверное значение температуры: %s (должно быть от -55 до 30)" + usage(_("Wrong temperature: %s (must be from -55 to 30)"), optarg); + } + set_T = TRUE; + // "Установить температуру: %.3f" + info(_("Set temperature: %.3f"), temperature); + break; + case 'v': + if (myatoi(&vbin, optarg) || vbin < 1 || vbin > 16){ + // "Неверный" + usage("%s vbin: %s", _("Wrong"), optarg); + } + // "Верт. биннинг: %d" + info(_("Vertical binning: %d"), vbin); + break; + case 'x': + if (myatoi(&exptime, optarg) || exptime < 0){ + // "Неверное время экспозиции: %s" + usage(_("Wrong exposure time: %s"), optarg); + } + // "Время экспозиции: %dмс" + info(_("Exposure time: %dms"), exptime); + break; + case 'X': + getrange(&X0, &X1, optarg); + // "Диапазон по X: [%d, %d]" + info(_("X range: [%d, %d]"), X0, X1); + break; + case 'Y': + getrange(&Y0, &Y1, optarg); + // "Диапазон по Y: [%d, %d]" + info(_("Y range: [%d, %d]"), Y0, Y1); + break; + default: + usage(NULL); + } + } + argc -= optind; + argv += optind; + if(argc == 0 && save_image){ + // "Нет префикса имени выходных файлов" + usage(_("Output file names prefix is absent")); + } + else{ if(argc != 0){ + outfile = argv[0]; + argc--; + argv++; + } + else outfile = strdup("nofile"); + } + if(argc > 0){ + // "Игнорирую аргумент[ы]:\n" + printf(_("Ignore argument[s]:\n")); + } + for (i = 0; i < argc; i++) + warnx("%s ", argv[i]); +} diff --git a/usage.h b/usage.h new file mode 100644 index 0000000..2f0afd0 --- /dev/null +++ b/usage.h @@ -0,0 +1,39 @@ +#ifndef __USAGE_H__ +#define __USAGE_H__ + +#include "takepic.h" +#include +#include + +extern int + exptime // время экспозиции (в мс) + ,pics // кол-во снимаемых кадров + ,hbin // горизонтальный биннинг + ,vbin // вертикальный биннинг + ,X0, X1, Y0, Y1 // координаты выбранного окна + ,flushes // кол-во сбросов + ,pause_len // продолжительность паузы (в с) между кадрами +; +extern double temperature; // температура (которую задать, потом - на начало эксп.) + +extern fliframe_t frametype; // тип фрейма (обычный или темновой) + +extern bool + only_T // только отобразить температуру - и выйти + ,set_T // задать нужную температуру + ,save_Tlog // сохранять журнал температур + ,save_image // сохранять изображение + ,stat_logging // полное логгирование статистики +; +extern char *objname // имя объекта + ,*outfile // префикс имени файла для записи raw/fits + ,*objtype // тип изображения + ,*instrument // название прибора (по умолчанию - "direct imaging") + ,*observers // наблюдатели + ,*prog_id // имя программы + ,*author // автор +; +void usage(char *fmt, ...); +void parse_args(int argc, char **argv); + +#endif // __USAGE_H__