|
RTS2
0.9.2-1
|
00001 /* 00002 * Basic camera daemon. 00003 * Copyright (C) 2001-2012 Petr Kubanek <petr@kubanek.net> 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #ifndef __RTS2_CAMERA_CPP__ 00021 #define __RTS2_CAMERA_CPP__ 00022 00023 #include <sys/time.h> 00024 #include <time.h> 00025 00026 #include "scriptdevice.h" 00027 #include "imghdr.h" 00028 00029 #define MAX_CHIPS 3 00030 #define MAX_DATA_RETRY 100 00031 00033 #define STATISTIC_YES 0 00034 #define STATISTIC_ONLY 1 00035 #define STATISTIC_NO 2 00036 00040 namespace rts2camd 00041 { 00042 00050 class Binning2D: public rts2core::Rts2SelData 00051 { 00052 public: 00056 int vertical; 00057 00061 int horizontal; 00062 00063 Binning2D (int in_vertical, int in_horizontal): Rts2SelData () 00064 { 00065 vertical = in_vertical; 00066 horizontal = in_horizontal; 00067 } 00068 00074 std::string getDescription () 00075 { 00076 std::ostringstream _os; 00077 _os << horizontal << "x" << vertical; 00078 return _os.str(); 00079 } 00080 }; 00081 00089 class DataType: public rts2core::Rts2SelData 00090 { 00091 public: 00092 int type; 00093 00094 DataType (int in_type): Rts2SelData () 00095 { 00096 type = in_type; 00097 } 00098 }; 00099 00100 class Camera; 00101 00112 class FilterVal 00113 { 00114 public: 00115 FilterVal (Camera *master, const char *n, char fil); 00116 // values are registered in class, hence autodeleted when class holding them is deleted - so there isn't class destructor 00117 rts2core::ValueSelection *filter; 00118 rts2core::DoubleArray *offsets; 00119 rts2core::ValueBool *moving; 00120 00121 const char *name; 00122 }; 00123 00196 class Camera:public rts2core::ScriptDevice 00197 { 00198 public: 00199 Camera (int argc, char **argv); 00200 virtual ~ Camera (void); 00201 00202 virtual int deleteConnection (rts2core::Connection * conn); 00210 virtual bool supportFrameTransfer (); 00211 00212 // end of CameraChip 00213 00214 virtual int initChips (); 00215 virtual int initValues (); 00216 void checkExposures (); 00217 void checkReadouts (); 00218 00219 virtual void deviceReady (rts2core::Connection * conn); 00220 00221 virtual void postEvent (rts2core::Event * event); 00222 00223 virtual void changeMasterState (int old_state, int new_state); 00224 00225 virtual int idle (); 00226 00227 virtual rts2core::DevClient *createOtherType (rts2core::Connection * conn, int other_device_type); 00228 virtual int info (); 00229 00230 virtual int killAll (bool callScriptEnds); 00231 virtual int scriptEnds (); 00232 00233 virtual long camWaitExpose (); 00234 00238 virtual int switchCooling (bool newval) { return 0; } 00239 00247 virtual int setCoolTemp (float new_temp) 00248 { 00249 tempSet->setValueDouble (new_temp); 00250 sendValueAll (tempSet); 00251 return 0; 00252 } 00253 00257 virtual void beforeNight () 00258 { 00259 if (nightCoolTemp && !isnan (nightCoolTemp->getValueFloat ())) 00260 { 00261 switchCooling (true); 00262 setCoolTemp (nightCoolTemp->getValueFloat ()); 00263 } 00264 } 00265 00269 virtual void afterNight () 00270 { 00271 switchCooling (false); 00272 } 00273 00280 virtual int readoutStart (); 00281 00282 int camReadout (rts2core::Connection * conn); 00283 00284 // focuser functions 00285 int setFocuser (int new_set); 00286 int getFocPos (); 00287 00288 bool isIdle (); 00289 00299 int getLastFilterNum () 00300 { 00301 return lastFilterNum; 00302 } 00303 00307 virtual int commandAuthorized (rts2core::Connection * conn); 00308 00309 virtual int maskQueValueBopState (int new_state, int valueQueCondition); 00310 00311 virtual void setFullBopState (int new_state); 00312 00313 protected: 00314 double pixelX; 00315 double pixelY; 00316 00317 // buffer used to read data 00318 char* getDataBuffer (int chan); 00319 char* getDataTop (int chan); 00320 00326 void addFilters (char *opt); 00327 00332 void addFilterOffsets (); 00333 00334 rts2core::ValueSelection * camFilterVal; 00335 rts2core::DoubleArray *camFilterOffsets; 00336 00337 rts2core::ValueString *filterOffsetFile; 00338 00339 // for multiple filter wheels 00340 std::list <FilterVal> camFilterVals; 00341 00347 double getExposureEnd () 00348 { 00349 return exposureEnd->getValueDouble (); 00350 } 00351 00358 void changeExposureEnd (double off) 00359 { 00360 exposureEnd->setValueDouble (exposureEnd->getValueDouble () + off); 00361 } 00362 00368 void nullExposureConn () { exposureConn = NULL; } 00369 00371 rts2core::ValueInteger *quedExpNumber; 00372 00376 rts2core::ValueSelection *expType; 00377 00384 void changeAxisDirections (bool x_orig, bool y_orig); 00385 00391 long getExposureNumber () { return exposureNumber->getValueLong (); } 00392 00393 long getScriptExposureNumber () { return scriptExposureNum->getValueLong (); } 00394 00398 void incExposureNumber () 00399 { 00400 exposureNumber->inc (); 00401 sendValueAll (exposureNumber); 00402 scriptExposureNum->inc (); 00403 sendValueAll (scriptExposureNum); 00404 } 00405 00406 const int getDataType () 00407 { 00408 return ((DataType *) dataType->getData ())->type; 00409 } 00410 00419 void setDataType (int ntype) { dataType->setValueInteger (ntype); } 00420 00425 void setDataTypeWritable () { dataType->setWritable (); } 00426 00427 int nAcc; 00428 struct imghdr *focusingHeader; 00429 00438 int sendImage (char *data, size_t dataSize); 00439 00440 int sendReadoutData (char *data, size_t dataSize, int chan = 0); 00441 00442 int fitsDataTransfer (const char *fn) 00443 { 00444 if (exposureConn) 00445 return exposureConn->fitsDataTransfer (fn); 00446 return 0; 00447 } 00448 00454 long getWriteBinaryDataSize () 00455 { 00456 if (currentImageData < 0 && calculateStatistics->getValueInteger () == STATISTIC_ONLY) 00457 // end bytes 00458 return calculateDataSize; 00459 if (exposureConn) 00460 return exposureConn->getWriteBinaryDataSize (currentImageData); 00461 return 0; 00462 } 00463 00469 long getWriteBinaryDataSize (int chan) 00470 { 00471 if (currentImageData < 0 && calculateStatistics->getValueInteger () == STATISTIC_ONLY) 00472 // end bytes 00473 return calculateDataSize; 00474 if (exposureConn) 00475 return exposureConn->getWriteBinaryDataSize (currentImageData, chan); 00476 return 0; 00477 } 00478 00479 void addBinning2D (int bin_v, int bin_h); 00480 00484 virtual void initBinnings (); 00485 00486 void addDataType (int in_type); 00487 00491 virtual void initDataTypes (); 00492 00496 int binningHorizontal () { return binningX->getValueInteger (); } 00497 00501 int binningVertical () { return binningY->getValueInteger (); } 00502 00508 const int usedPixelByteSize () 00509 { 00510 if (getDataType () == RTS2_DATA_ULONG) 00511 return 4; 00512 return abs (getDataType () / 8); 00513 } 00514 00518 const int maxPixelByteSize (); 00519 00527 size_t chipUsedSize () { return getUsedWidthBinned () * getUsedHeightBinned (); } 00528 00529 size_t getReadoutPixels () { return readoutPixels; } 00530 00531 00537 virtual size_t chipByteSize () { return chipUsedSize () * usedPixelByteSize (); } 00538 00542 size_t lineByteSize () { return usedPixelByteSize () * (chipUsedReadout->getWidthInt ()); } 00543 00544 virtual int processData (char *data, size_t size); 00545 00546 rts2core::ValueRectangle *chipUsedReadout; 00547 00556 virtual int processOption (int in_opt); 00557 00558 virtual void usage (); 00559 00560 int willConnect (rts2core::NetworkAddress * in_addr); 00561 char *device_file; 00562 // number of data channels 00563 rts2core::ValueInteger *dataChannels; 00564 // which channels are off (and which are on) 00565 rts2core::BoolArray *channels; 00566 00567 rts2core::ValueBool *coolingOnOff; 00568 // temperature and others; all in deg Celsius 00569 rts2core::ValueFloat *tempAir; 00570 rts2core::ValueFloat *tempCCD; 00571 rts2core::ValueDoubleStat *tempCCDHistory; 00572 rts2core::ValueInteger *tempCCDHistoryInterval; 00573 rts2core::ValueInteger *tempCCDHistorySize; 00574 rts2core::ValueDoubleMinMax *tempSet; 00575 00576 // night cooling temperature 00577 rts2core::ValueFloat *nightCoolTemp; 00578 00579 char ccdType[64]; 00580 char *ccdRealType; 00581 char serialNumber[64]; 00582 00583 virtual void checkQueChanges (int fakeState); 00584 00585 void checkQueuedExposures (); 00586 00587 void initCameraChip (); 00588 void initCameraChip (int in_width, int in_height, double in_pixelX, double in_pixelY); 00589 00597 virtual int startExposure () = 0; 00598 00599 virtual void afterReadout (); 00600 00601 virtual int endReadout (); 00602 00616 virtual int doReadout () = 0; 00617 00618 void clearReadout (); 00619 00620 void setSize (int in_width, int in_height, int in_x, int in_y) 00621 { 00622 chipSize->setInts (in_x, in_y, in_width, in_height); 00623 chipUsedReadout->setInts (in_x, in_y, in_width, in_height); 00624 } 00625 00626 void setUsedHeight (int in_height) 00627 { 00628 chipUsedReadout->setHeight (in_height); 00629 } 00630 00640 virtual size_t suggestBufferSize () { return chipByteSize (); } 00641 00647 const int getWidth () { return chipSize->getWidthInt (); } 00648 00654 const int getUsedWidth () { return chipUsedReadout->getWidthInt (); } 00655 00661 const int getUsedWidthBinned () { return (int) (ceil (getUsedWidth () / binningHorizontal ())); } 00662 00668 const int getUsedRowBytes () { return getUsedWidthBinned () * usedPixelByteSize (); } 00669 00675 const int getHeight () { return chipSize->getHeightInt (); } 00676 00681 const int getUsedY () { return chipUsedReadout->getYInt (); } 00682 00687 const int getUsedX () { return chipUsedReadout->getXInt (); } 00688 00694 const int getUsedHeight () { return chipUsedReadout->getHeightInt (); } 00695 00701 const int getUsedHeightBinned () { return (int) (ceil (getUsedHeight () / binningVertical ())); } 00702 00708 const int chipTopX () { return chipUsedReadout->getXInt (); } 00709 00715 const int chipTopY () { return chipUsedReadout->getYInt (); } 00716 00717 virtual int setBinning (int in_vert, int in_hori); 00718 00719 int center (int in_w, int in_h); 00720 00727 virtual long isExposing (); 00728 00734 virtual int endExposure (); 00735 00741 virtual int stopExposure (); 00742 00743 virtual int setValue (rts2core::Value * old_value, rts2core::Value * new_value); 00744 00745 virtual void valueChanged (rts2core::Value *changed_value); 00746 00750 void createExpType () 00751 { 00752 createValue (expType, "SHUTTER", "shutter state", true, RTS2_VALUE_WRITABLE); 00753 expType->addSelVal ("LIGHT", NULL); 00754 expType->addSelVal ("DARK", NULL); 00755 } 00756 00763 void createFilter (bool working = false) 00764 { 00765 if (camFilterVal == NULL) 00766 createValue (camFilterVal, "filter", "used filter number", false, RTS2_VALUE_WRITABLE, working ? CAM_WORKING : CAM_EXPOSING); 00767 if (camFilterOffsets == NULL) 00768 createValue (camFilterOffsets, "filter_offsets", "filter offsets", false, RTS2_VALUE_WRITABLE); 00769 } 00770 00777 void addShutterType (const char *enumName, rts2core::Rts2SelData *data = NULL) { expType->addSelVal (enumName, data); } 00778 00782 void createDataChannels () 00783 { 00784 createValue (dataChannels, "DATA_CHANNELS", "total number of data channels", true); 00785 createValue (channels, "CHAN", "channels on/off", true, RTS2_DT_ONOFF | RTS2_VALUE_WRITABLE | RTS2_FITS_HEADERS, CAM_WORKING); 00786 } 00787 00788 void setNumChannels (int num) 00789 { 00790 channels->clear (); 00791 for (int i = 0; i < num; i++) 00792 channels->addValue (true); 00793 } 00794 00795 int getNumChannels () 00796 { 00797 if (channels == NULL) 00798 return 1; 00799 return channels->size (); 00800 } 00801 00806 void createTempAir () { createValue (tempAir, "CCD_AIR", "detector air temperature"); } 00807 00811 void createTempCCD () { createValue (tempCCD, "CCD_TEMP", "CCD temperature"); } 00812 00816 void createTempCCDHistory () { 00817 createValue (tempCCDHistory, "ccd_temp_history", "history of ccd temperatures", false); 00818 createValue (tempCCDHistoryInterval, "ccd_temp_interval", "interval in seconds between repeative queries of CCD temperature", false); 00819 createValue (tempCCDHistorySize, "ccd_temp_size", "interval in seconds between repeative queries of CCD temperature", false); 00820 00821 tempCCDHistoryInterval->setValueInteger (2); 00822 tempCCDHistorySize->setValueInteger (20); 00823 } 00824 00828 void addTempCCDHistory (float temp); 00829 00833 virtual void temperatureCheck () {}; 00834 00840 void createTempSet () 00841 { 00842 createValue (coolingOnOff, "COOLING", "camera cooling start/stop", true, RTS2_VALUE_WRITABLE | RTS2_DT_ONOFF, CAM_WORKING); 00843 createValue (tempSet, "CCD_SET", "CCD set temperature", true, RTS2_VALUE_WRITABLE, CAM_WORKING); 00844 createValue (nightCoolTemp, "nightcool", "night cooling temperature", false, RTS2_VALUE_WRITABLE); 00845 nightCoolTemp->setValueFloat (NAN); 00846 addOption ('c', NULL, 1, "night cooling temperature"); 00847 } 00848 00854 double getExposure () { return exposure->getValueDouble (); } 00855 00859 void setExposureMinMax (double exp_min, double exp_max); 00860 00864 virtual void setExposure (double exp) { exposure->setValueDouble (exp); } 00865 00871 int getExpType () { return expType->getValueInteger (); } 00872 00878 virtual int setFilterNum (int new_filter, const char *fn = NULL); 00879 virtual int getFilterNum (const char *fn = NULL); 00880 00881 void offsetForFilter (int new_filter, std::list <FilterVal>::iterator fvi); 00882 00883 int getCamFilterNum () { return camFilterVal->getValueInteger (); } 00884 00885 void setFilterWorking (bool working) { getCondValue (camFilterVal)->setStateCondition (working ? CAM_WORKING : CAM_EXPOSING); } 00886 00890 void markReadoutStart () { timeReadoutStart = getNow (); } 00891 00895 void updateReadoutSpeed (size_t computedPixels) 00896 { 00897 if (!isnan (timeReadoutStart)) 00898 { 00899 readoutTime->setValueDouble (getNow () - timeReadoutStart); 00900 sendValueAll (readoutTime); 00901 00902 pixelsSecond->setValueDouble (computedPixels / readoutTime->getValueDouble ()); 00903 sendValueAll (pixelsSecond); 00904 00905 // end computation of readout time 00906 if (computedPixels >= readoutPixels) 00907 timeReadoutStart = NAN; 00908 } 00909 } 00910 00911 void setFitsTransfer () { currentImageTransfer = FITS; } 00912 00913 private: 00914 size_t readoutPixels; 00915 // data buffers - separated for each channel 00916 char** dataBuffers; 00917 size_t *dataWritten; 00918 00919 // readout - ideally time for data->computer. Camera driver should start markReadoutStart and markReadoutEnd to mark start/end times 00920 double timeReadoutStart; 00921 // readout time including transfer (TCP/IP,..) overhead 00922 double timeTransferStart; 00923 00924 // focusing header data 00925 struct imghdr *fhd; 00926 00927 // physical readout time from device 00928 rts2core::ValueDouble *pixelsSecond; 00929 rts2core::ValueDouble *readoutTime; 00930 00931 // data time including transfer overhead 00932 rts2core::ValueDouble *transferTime; 00933 00934 // connection which requries data to be send after end of exposure 00935 rts2core::Connection *exposureConn; 00936 00937 rts2core::ValueDoubleMinMax *exposure; 00938 00939 // shared memory identifier 00940 int sharedMemNum; 00941 rts2core::DataSharedWrite *sharedData; 00942 00943 // number of exposures camera takes 00944 rts2core::ValueLong *exposureNumber; 00945 // exposure number inside script 00946 rts2core::ValueLong *scriptExposureNum; 00947 rts2core::ValueBool *waitingForEmptyQue; 00948 rts2core::ValueBool *waitingForNotBop; 00949 00950 rts2core::ValueInteger *binningX; 00951 rts2core::ValueInteger *binningY; 00952 00953 char *focuserDevice; 00954 std::vector < const char * > wheelDevices; 00955 00956 int lastFilterNum; 00957 00958 int currentImageData; 00959 // true if current image is send over shared connection 00960 enum { TCPIP, SHARED, FITS } currentImageTransfer; 00961 00962 // whenewer statistics should be calculated 00963 rts2core::ValueSelection *calculateStatistics; 00964 00965 // image parameters 00966 rts2core::ValueDouble *average; 00967 rts2core::ValueDouble *min; 00968 rts2core::ValueDouble *max; 00969 rts2core::ValueDouble *sum; 00970 00971 rts2core::ValueLong *computedPix; 00972 00976 rts2core::ValueBool *calculateCenter; 00977 00982 rts2core::ValueRectangle *centerBox; 00983 00984 rts2core::ValueDouble *centerCutLevel; 00985 00986 rts2core::DoubleArray *sumsX; 00987 rts2core::DoubleArray *sumsY; 00988 00989 // center values 00990 rts2core::ValueDouble *centerX; 00991 rts2core::ValueDouble *centerY; 00992 00993 // update statistics 00994 template <typename t> int updateStatistics (t *data, size_t dataSize) 00995 { 00996 long double tSum = 0; 00997 double tMin = min->getValueDouble (); 00998 double tMax = max->getValueDouble (); 00999 int pixNum = 0; 01000 t *tData = data; 01001 while (((char *) tData) < ((char *) data) + dataSize) 01002 { 01003 t tD = *tData; 01004 tSum += tD; 01005 if (tD < tMin) 01006 tMin = tD; 01007 if (tD > tMax) 01008 tMax = tD; 01009 tData++; 01010 pixNum++; 01011 } 01012 sum->setValueDouble (sum->getValueDouble () + tSum); 01013 if (tMin < min->getValueDouble ()) 01014 min->setValueDouble (tMin); 01015 if (tMax > max->getValueDouble ()) 01016 max->setValueDouble (tMax); 01017 return pixNum; 01018 } 01019 01020 // update center box 01021 template <typename t> int updateCenter (t *data, size_t dataSize) 01022 { 01023 // check if box is inside window 01024 int x = centerBox->getXInt (); 01025 if (x < 0) 01026 x = getUsedX (); 01027 int y = centerBox->getYInt (); 01028 if (y < 0) 01029 y = getUsedY (); 01030 int w = centerBox->getWidthInt () / binningHorizontal (); 01031 if (w < 0) 01032 w = (getUsedWidth () - (x - getUsedX ())) / binningHorizontal (); 01033 int h = centerBox->getHeightInt () / binningVertical (); 01034 if (h < 0) 01035 h = (getUsedHeight () - (y - getUsedY ())) / binningVertical (); 01036 01037 x -= getUsedX (); 01038 y -= getUsedY (); 01039 01040 if (x < 0 || y < 0 || (w + ceil ((double) x / binningHorizontal ())) > getUsedWidthBinned () || (h + ceil ((double) y / binningVertical ())) > getUsedHeightBinned ()) 01041 return -1; 01042 01043 t *tData = data; 01044 // move to the first calculated pixel 01045 tData += y * getUsedWidthBinned () + x; 01046 01047 int i; 01048 01049 double sx[w]; 01050 for (i = 0; i < w; i++) 01051 sx[i] = 0; 01052 01053 sumsY->clear (); 01054 01055 for (int row = 0; row < h; row++) 01056 { 01057 double rs = 0; 01058 for (int col = 0; col < w; col++, tData++) 01059 { 01060 if (*tData >= centerCutLevel->getValueDouble ()) 01061 { 01062 sx[col] += *tData; 01063 rs += *tData; 01064 } 01065 } 01066 01067 sumsY->addValue (rs); 01068 } 01069 01070 sumsX->clear (); 01071 01072 for (i = 0; i < w; i++) 01073 sumsX->addValue (sx[i]); 01074 01075 sendValueAll (sumsX); 01076 sendValueAll (sumsY); 01077 01078 centerX->setValueDouble (sumsX->calculateMedianIndex ()); 01079 centerY->setValueDouble (sumsY->calculateMedianIndex ()); 01080 01081 sendValueAll (centerX); 01082 sendValueAll (centerY); 01083 01084 return 0; 01085 } 01086 01087 char multi_wcs; 01088 01089 // WCS CRPIX 01090 rts2core::ValueDouble *wcs_crpix1; 01091 rts2core::ValueDouble *wcs_crpix2; 01092 01093 double default_crpix[2]; 01094 01095 // WCS CD matrix 01096 rts2core::ValueString *wcs_ctype1; 01097 rts2core::ValueString *wcs_ctype2; 01098 rts2core::ValueDouble *wcs_cdelta1; 01099 rts2core::ValueDouble *wcs_cdelta2; 01100 rts2core::ValueDouble *wcs_crota; 01101 01102 // 1:1 binning, default WCS - cdelta1,cdelta2,crota 01103 double default_cd[3]; 01104 01105 rts2core::ValueRectangle *chipSize; 01106 01107 int camStartExposure (); 01108 int camStartExposureWithoutCheck (); 01109 01110 rts2core::ValueInteger *camFocVal; 01111 01112 int getStateChip (int chip); 01113 01114 // chip binning 01115 rts2core::ValueSelection *binning; 01116 01117 // allowed chip data type 01118 rts2core::ValueSelection *dataType; 01119 01120 // when chip exposure will end 01121 rts2core::ValueTime *exposureEnd; 01122 01123 // filter wheel is moving 01124 rts2core::ValueBool *focuserMoving; 01125 01126 // set chipUsedSize size 01127 int box (int _x, int _y, int _width, int _height, rts2core::ValueRectangle *retv = NULL); 01128 01129 // callback functions from camera connection 01130 int camExpose (rts2core::Connection * conn, int chipState, bool fromQue); 01131 int camBox (rts2core::Connection * conn, int x, int y, int width, int height); 01132 int camCenter (rts2core::Connection * conn, int in_w, int in_h); 01133 01140 int getPhysicalChannel (int ch); 01141 01142 void startImageData (rts2core::Connection * conn); 01143 01148 int sendFirstLine (int chan, int pchan); 01149 01150 // if true, send command OK after exposure is started 01151 bool sendOkInExposure; 01152 01153 long calculateDataSize; 01154 01155 void setFilterOffsets (char *opt); 01156 01157 bool filterMoving (); 01158 01159 void setFilterOffsetFile (const char *filename); 01160 01161 std::map <std::string, double> filterOffsets; 01162 }; 01163 01164 } 01165 01166 #endif /* !__RTS2_CAMERA_CPP__ */