diff --git a/FLI_cameras/fliusb.rules b/FLI_cameras/fliusb.rules new file mode 100644 index 0000000..ed3fc37 --- /dev/null +++ b/FLI_cameras/fliusb.rules @@ -0,0 +1,5 @@ +ACTION!="add", GOTO="EOF" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="0f18", ATTRS{idProduct}=="000a", MODE:="0666", SYMLINK+="flicam" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="0f18", ATTRS{idProduct}=="0007", MODE:="0666", SYMLINK+="flifilter" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="0f18", ATTRS{idProduct}=="0006", MODE:="0666", SYMLINK+="flifocuser" +LABEL="EOF" diff --git a/Readme.md b/Readme.md index a2977d8..5dd3767 100644 --- a/Readme.md +++ b/Readme.md @@ -1,2 +1,81 @@ -# CCD_Capture -CCD/CMOS capturing tool for different models +CCD/CMOS imaging server +======================= + +Supports FLI cameras/focusers/wheels and ZWO cameras. +Allows to run as standalone application or imaging server/client. + +To restart server (e.g. if hardware was off) kill it with SIGUSR1 + +## Compile + +cmake options: + +- `-DDEBUG=yes` -- make with a lot debugging info +- `-DIMAGEVIEW=yes -- compile with image viewer support (only for standalone) (OpenGL!!!) +- `-DZWO=yes` -- compile ZWO support plugin +- `-DFLI=yes` -- compile FLI support plugin + + + +``` +Usage: ccd_capture [args] [output file prefix] + Args are: + + -8, --8bit run in 8-bit mode + -A, --author=arg program author + -C, --cameradev=arg camera device plugin (e.g. devfli.so) + -D, --display Display image in OpenGL window + -F, --focuserdev=arg focuser device plugin (e.g. devzwo.so) + -I, --instrument=arg instrument name + -L, --list list connected devices + -N, --obsname=arg observers' names + -O, --object=arg object name + -P, --prog-id=arg observing program name + -V, --verbose verbose level (-V - messages, -VV - debug, -VVV - all shit) + -W, --wheeldev=arg wheel device plugin (e.g. devdummy.so) + -Y, --objtype=arg object type (neon, object, flat etc) + -a, --addsteps=arg move focuser to relative position, mm (only for standalone) + -c, --conf-ioport=arg configure I/O port pins to given value (decimal number, pin1 is LSB, 1 == output, 0 == input) + -d, --dark not open shutter, when exposing ("dark frames") + -f, --fast fast readout mode + -g, --goto=arg move focuser to absolute position, mm + -h, --hbin=arg horizontal binning to N pixels + -i, --get-ioport get value of I/O port pins + -l, --nflushes=arg N flushes before exposing (default: 1) + -n, --nframes=arg make series of N frames + -o, --outfile=arg output file name + -p, --pause=arg make pause for N seconds between expositions + -r, --addrec add records to header from given file[s] + -s, --set-ioport=arg set I/O port pins to given value (decimal number, pin1 is LSB) + -t, --set-temp=arg set CCD temperature to given value (degr C) + -v, --vbin=arg vertical binning to N pixels + -w, --wheel-set=arg set wheel position + -x, --exptime=arg set exposure time to given value (seconds!) + --X0=arg absolute (not divided by binning!) frame X0 coordinate (-1 - all with overscan) + --X1=arg absolute frame X1 coordinate (-1 - all with overscan) + --Y0=arg absolute frame Y0 coordinate (-1 - all with overscan) + --Y1=arg absolute frame Y1 coordinate (-1 - all with overscan) + --async move stepper motor asynchronous + --brightness=arg CMOS brightness level + --camdevno=arg camera device number (if many: 0, 1, 2 etc) + --cancel cancel current exposition + --client run as client + --close-shutter close shutter + --focdevno=arg focuser device number (if many: 0, 1, 2 etc) + --gain=arg CMOS gain level + --help show this help + --logfile=arg logging file name (if run as server) + --open-shutter open shutter + --path=arg UNIX socket name + --pidfile=arg PID file (default: /tmp/CCD_Capture.pid) + --plugin=arg common device plugin (e.g devfli.so) + --port=arg local INET socket port + --restart restart image server + --rewrite rewrite output file if exists + --set-fan=arg set fan speed (0 - off, 1 - low, 2 - high) + --shutter-on-high run exposition on HIGH @ pin5 I/O port + --shutter-on-low run exposition on LOW @ pin5 I/O port + --wait wait while exposition ends + --wheeldevno=arg filter wheel device number (if many: 0, 1, 2 etc) +``` + diff --git a/ZWO_cameras/asi.rules b/ZWO_cameras/asi.rules new file mode 100644 index 0000000..1d2581a --- /dev/null +++ b/ZWO_cameras/asi.rules @@ -0,0 +1,3 @@ +SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="03c3", RUN+="/bin/sh -c '/bin/echo 200 >/sys/module/usbcore/parameters/usbfs_memory_mb'", MODE="0666" + +#SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="03c3", RUN+="/etc/udev/rules.d/sc" diff --git a/ccdfunc.c b/ccdfunc.c index 039e120..a586bce 100644 --- a/ccdfunc.c +++ b/ccdfunc.c @@ -48,7 +48,7 @@ do{ int status = 0; \ }while(0) #define WRITEKEY(...) \ do{ int status = 0; \ - fits_write_key(__VA_ARGS__, &status); \ + fits_update_key(__VA_ARGS__, &status); \ if(status) fits_report_error(stderr, status);\ }while(0) @@ -118,31 +118,59 @@ static int check_filenameprefix(char *buff, int buflen){ return FALSE; } +// get next record from external text file, newlines==1 if every record ends with '\n' +static char *getnextrec(char *buf, char *record, int newlines){ + char *nextline = NULL; + int l = FLEN_CARD - 1; + if(newlines){ + char *e = strchr(buf, '\n'); + if(e){ + if(e - buf < FLEN_CARD) l = e - buf; + nextline = e + 1; + } + }else nextline = buf + (FLEN_CARD - 1); + strncpy(record, buf, l); + record[l] = 0; + return nextline; +} + /** * @brief addrec - add FITS records from file * @param f (i) - FITS filename * @param filename (i) - name of file */ static void addrec(fitsfile *f, char *filename){ - FILE *fp = fopen(filename, "r"); - if(!fp) return; - char buf[2*FLEN_CARD]; - while(fgets(buf, 2*FLEN_CARD, fp)){ - //DBG("check record _%s_", buf); + mmapbuf *buf = My_mmap(filename); + char rec[FLEN_CARD]; + if(!buf || buf->len < 1){ + WARNX("Empty header file %s", filename); + return; + } + char *data = buf->data, *x = strchr(data, '\n'), *eodata = buf->data + buf->len; + int newlines = 0; + if(x && (x - data) < FLEN_CARD){ // we found newline -> this is a format with newlines + newlines = 1; + } + do{ + data = getnextrec(data, rec, newlines); + verbose(4, "check record _%s_", rec); int keytype, status = 0; char newcard[FLEN_CARD], keyname[FLEN_CARD]; - fits_parse_template(buf, newcard, &keytype, &status); + fits_parse_template(rec, newcard, &keytype, &status); if(status){ fits_report_error(stderr, status); continue; } - //DBG("reformatted to _%s_", newcard); + verbose(4, "reformatted to _%s_", newcard); strncpy(keyname, newcard, FLEN_CARD); char *eq = strchr(keyname, '='); if(eq) *eq = 0; eq = strchr(keyname, ' '); if(eq) *eq = 0; //DBG("keyname: %s", keyname); fits_update_card(f, keyname, newcard, &status); - } + if(status) fits_report_error(stderr, status); + if(data > eodata) break; + }while(data && *data); + My_munmap(buf); } // save FITS file `img` into GP->outfile or GP->outfileprefix_XXXX.fits @@ -196,24 +224,11 @@ int saveFITS(IMG *img, char **outp){ if(fitserror) goto cloerr; TRYFITS(fits_create_img, fp, USHORT_IMG, 2, naxes); if(fitserror) goto cloerr; - // FILE / Input file original name - WRITEKEY(fp, TSTRING, "FILE", fnam, "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->getModelName(buff, PATH_MAX)){ - WRITEKEY(fp, TSTRING, "DETECTOR", buff, "Detector model"); - } - // INSTRUME / Instrument - if(GP->instrument){ - WRITEKEY(fp, TSTRING, "INSTRUME", GP->instrument, "Instrument"); - }else - WRITEKEY(fp, TSTRING, "INSTRUME", "direct imaging", "Instrument"); - snprintf(bufc, FLEN_VALUE, "%g x %g", camera->pixX, camera->pixY); - // PXSIZE / pixel size - WRITEKEY(fp, TSTRING, "PXSIZE", bufc, "Pixel size in m"); + WRITEKEY(fp, TSTRING, "INSTRUME", "direct imaging", "Instrument"); snprintf(bufc, FLEN_VALUE, "(%d, %d)(%d, %d)", camera->field.xoff, camera->field.yoff, camera->field.xoff + camera->field.w, camera->field.yoff + camera->field.h); WRITEKEY(fp, TSTRING, "VIEWFLD", bufc, "Camera maximal field of view"); @@ -272,10 +287,6 @@ int saveFITS(IMG *img, char **outp){ WRITEKEY(fp, TSTRING, "DATE-OBS", bufc, "DATE OF OBS. (YYYY/MM/DD, local)"); strftime(bufc, 80, "%H:%M:%S", tm_time); WRITEKEY(fp, TSTRING, "TIME", bufc, "Creation time (hh:mm:ss, local)"); - // OBJECT / Object name - if(GP->objname){ - WRITEKEY(fp, TSTRING, "OBJECT", GP->objname, "Object name"); - } // BINNING / Binning if(GP->hbin != 1 || GP->vbin != 1){ snprintf(bufc, 80, "%d x %d", GP->hbin, GP->vbin); @@ -285,18 +296,6 @@ int saveFITS(IMG *img, char **outp){ tmpi = GP->vbin; WRITEKEY(fp, TINT, "YBINNING", &tmpi, "binning factor used on Y axis"); } - // OBSERVER / Observers - if(GP->observers){ - WRITEKEY(fp, TSTRING, "OBSERVER", GP->observers, "Observers"); - } - // PROG-ID / Observation program identifier - if(GP->prog_id){ - WRITEKEY(fp, TSTRING, "PROG-ID", GP->prog_id, "Observation program identifier"); - } - // AUTHOR / Author of the program - if(GP->author){ - WRITEKEY(fp, TSTRING, "AUTHOR", GP->author, "Author of the program"); - } if(focuser){ // there is a focuser device - add info if(focuser->getModelName(buff, PATH_MAX)) WRITEKEY(fp, TSTRING, "FOCUSER", buff, "Focuser model"); @@ -325,6 +324,30 @@ int saveFITS(IMG *img, char **outp){ addrec(fp, *nxtfile++); } } + // add these keywords after all to change things in files with static records + // OBSERVER / Observers + if(GP->observers) + WRITEKEY(fp, TSTRING, "OBSERVER", GP->observers, "Observers"); + // PROG-ID / Observation program identifier + if(GP->prog_id) + WRITEKEY(fp, TSTRING, "PROG-ID", GP->prog_id, "Observation program identifier"); + // AUTHOR / Author of the program + if(GP->author) + WRITEKEY(fp, TSTRING, "AUTHOR", GP->author, "Author of the program"); + // OBJECT / Object name + if(GP->objname){ + WRITEKEY(fp, TSTRING, "OBJECT", GP->objname, "Object name"); + } + // FILE / Input file original name + char *n = fnam; + if(*n == '!') ++n; + WRITEKEY(fp, TSTRING, "FILE", n, "Input file original name"); + // DETECTOR / detector + if(camera->getModelName(buff, PATH_MAX)) + WRITEKEY(fp, TSTRING, "DETECTOR", buff, "Detector model"); + // INSTRUME / Instrument + if(GP->instrument) + WRITEKEY(fp, TSTRING, "INSTRUME", GP->instrument, "Instrument"); TRYFITS(fits_write_img, fp, TUSHORT, 1, width * height, data); if(fitserror) goto cloerr; TRYFITS(fits_close_file, fp);