Instrument Neutral Distributed Interface INDI  1.1.0
indiccd.cpp
1 /*******************************************************************************
2  Copyright(c) 2010, 2011 Gerry Rozema, Jasem Mutlaq. All rights reserved.
3 
4  Rapid Guide support added by CloudMakers, s. r. o.
5  Copyright(c) 2013 CloudMakers, s. r. o. All rights reserved.
6 
7  Star detection algorithm is based on PHD Guiding by Craig Stark
8  Copyright (c) 2006-2010 Craig Stark. All rights reserved.
9 
10  This library is free software; you can redistribute it and/or
11  modify it under the terms of the GNU Library General Public
12  License version 2 as published by the Free Software Foundation.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Library General Public License for more details.
18 
19  You should have received a copy of the GNU Library General Public License
20  along with this library; see the file COPYING.LIB. If not, write to
21  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  Boston, MA 02110-1301, USA.
23 *******************************************************************************/
24 
25 #include "indiccd.h"
26 
27 #include <string.h>
28 #include <time.h>
29 #include <sys/time.h>
30 #include <zlib.h>
31 #include <errno.h>
32 #include <dirent.h>
33 
34 #include <libnova.h>
35 #include <fitsio.h>
36 
37 const char *IMAGE_SETTINGS_TAB = "Image Settings";
38 const char *IMAGE_INFO_TAB = "Image Info";
39 const char *GUIDE_HEAD_TAB = "Guider Head";
40 const char *GUIDE_CONTROL_TAB = "Guider Control";
41 const char *RAPIDGUIDE_TAB = "Rapid Guide";
42 const char *WCS_TAB = "WCS";
43 
44 CCDChip::CCDChip()
45 {
46  SendCompressed=false;
47  Interlaced=false;
48 
49  RawFrame= (char *) malloc(sizeof(char)); // Seed for realloc
50  RawFrameSize=0;
51 
52  BPP = 8;
53  BinX = BinY = 1;
54  NAxis = 2;
55 
56  strncpy(imageExtention, "fits", MAXINDIBLOBFMT);
57 
58  FrameType=LIGHT_FRAME;
59  lastRapidX = lastRapidY = -1;
60 }
61 
62 CCDChip::~CCDChip()
63 {
64  delete RawFrame;
65  RawFrameSize=0;
66  RawFrame=NULL;
67 
68 }
69 
70 void CCDChip::setFrameType(CCD_FRAME type)
71 {
72  FrameType=type;
73 }
74 
75 void CCDChip::setResolution(int x, int y)
76 {
77  XRes = x;
78  YRes = y;
79 
80  ImagePixelSizeN[0].value=x;
81  ImagePixelSizeN[1].value=y;
82 
83  IDSetNumber(&ImagePixelSizeNP, NULL);
84 
85  ImageFrameN[FRAME_X].min = 0;
86  ImageFrameN[FRAME_X].max = x-1;
87  ImageFrameN[FRAME_Y].min = 0;
88  ImageFrameN[FRAME_Y].max = y-1;
89 
90  ImageFrameN[FRAME_W].min = 1;
91  ImageFrameN[FRAME_W].max = x;
92  ImageFrameN[FRAME_H].max = 1;
93  ImageFrameN[FRAME_H].max = y;
94  IUUpdateMinMax(&ImageFrameNP);
95 }
96 
97 void CCDChip::setFrame(int subx, int suby, int subw, int subh)
98 {
99  SubX = subx;
100  SubY = suby;
101  SubW = subw;
102  SubH = subh;
103 
104  ImageFrameN[FRAME_X].value = SubX;
105  ImageFrameN[FRAME_Y].value = SubY;
106  ImageFrameN[FRAME_W].value = SubW;
107  ImageFrameN[FRAME_H].value = SubH;
108 
109  IDSetNumber(&ImageFrameNP, NULL);
110 }
111 
112 void CCDChip::setBin(int hor, int ver)
113 {
114  BinX = hor;
115  BinY = ver;
116 
117  ImageBinN[BIN_W].value = BinX;
118  ImageBinN[BIN_H].value = BinY;
119 
120  IDSetNumber(&ImageBinNP, NULL);
121 }
122 
123 
124 void CCDChip::setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient)
125 {
126  INumberVectorProperty *nvp = NULL;
127 
128  if (!strcmp(property, ImageExposureNP.name))
129  nvp = &ImageExposureNP;
130  else if (!strcmp(property, ImageFrameNP.name))
131  nvp = &ImageFrameNP;
132  else if (!strcmp(property, ImageBinNP.name))
133  nvp = &ImageBinNP;
134  else if (!strcmp(property, ImagePixelSizeNP.name))
135  nvp = &ImagePixelSizeNP;
136  else if (!strcmp(property, RapidGuideDataNP.name))
137  nvp = &RapidGuideDataNP;
138 
139  INumber *np = IUFindNumber(nvp, element);
140  if (np)
141  {
142  np->min = min;
143  np->max = max;
144  np->step = step;
145 
146  if (sendToClient)
147  IUUpdateMinMax(nvp);
148  }
149 
150 }
151 
152 void CCDChip::setPixelSize(float x, float y)
153 {
154  PixelSizex = x;
155  PixelSizey = y;
156 
157  ImagePixelSizeN[2].value=x;
158  ImagePixelSizeN[3].value=x;
159  ImagePixelSizeN[4].value=y;
160 
161  IDSetNumber(&ImagePixelSizeNP, NULL);
162 
163 }
164 
165 void CCDChip::setBPP(int bbp)
166 {
167  BPP = bbp;
168 
169  ImagePixelSizeN[5].value = BPP;
170 
171  IDSetNumber(&ImagePixelSizeNP, NULL);
172 }
173 
174 void CCDChip::setFrameBufferSize(int nbuf, bool allocMem)
175 {
176  if (nbuf == RawFrameSize)
177  return;
178 
179  RawFrameSize = nbuf;
180 
181  if (allocMem == false)
182  return;
183 
184  RawFrame = (char *) realloc(RawFrame, nbuf * sizeof(char));
185 }
186 
187 void CCDChip::setExposureLeft(double duration)
188 {
189  ImageExposureN[0].value = duration;
190 
191  IDSetNumber(&ImageExposureNP, NULL);
192 }
193 
194 void CCDChip::setExposureDuration(double duration)
195 {
196  exposureDuration = duration;
197  gettimeofday(&startExposureTime,NULL);
198 }
199 
200 const char *CCDChip::getFrameTypeName(CCD_FRAME fType)
201 {
202  return FrameTypeS[fType].name;
203 }
204 
206 {
207  static char ts[32];
208  struct tm *tp;
209  time_t t = (time_t) startExposureTime.tv_sec;
210 
211  //time (&t);
212  tp = gmtime (&t);
213  strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp);
214  return (ts);
215 }
216 
217 void CCDChip::setInterlaced(bool intr)
218 {
219  Interlaced = intr;
220 }
221 
223 {
224  ImageExposureNP.s = IPS_ALERT;
225  IDSetNumber(&ImageExposureNP, NULL);
226 }
227 
228 int CCDChip::getNAxis() const
229 {
230  return NAxis;
231 }
232 
233 void CCDChip::setNAxis(int value)
234 {
235  NAxis = value;
236 }
237 
238 void CCDChip::setImageExtension(const char *ext)
239 {
240  strncpy(imageExtention, ext, MAXINDIBLOBFMT);
241 }
242 
243 INDI::CCD::CCD()
244 {
245  //ctor
246  capability.hasGuideHead=false;
247  capability.hasST4Port=false;
248  capability.hasShutter=false;
249  capability.hasCooler=false;
250  capability.canBin=false;
251  capability.canSubFrame=false;
252  capability.canAbort=false;
253  capability.hasBayer;
254 
255  InExposure=false;
256  InGuideExposure=false;
257  RapidGuideEnabled=false;
258  GuiderRapidGuideEnabled=false;
259  ValidCCDRotation=false;
260 
261  AutoLoop=false;
262  SendImage=false;
263  ShowMarker=false;
264  GuiderAutoLoop=false;
265  GuiderSendImage=false;
266  GuiderShowMarker=false;
267 
268  ExposureTime = 0.0;
269  GuiderExposureTime = 0.0;
270  CurrentFilterSlot=-1;
271 
272  RA=-1000;
273  Dec=-1000;
274  Aperture=FocalLength=-1;
275 }
276 
277 INDI::CCD::~CCD()
278 {
279 
280 }
281 
283 {
284  capability.canAbort = cap->canAbort;
285  capability.canBin = cap->canBin;
286  capability.canSubFrame = cap->canSubFrame;
287  capability.hasCooler = cap->hasCooler;
288  capability.hasGuideHead = cap->hasGuideHead;
289  capability.hasShutter = cap->hasShutter;
290  capability.hasST4Port = cap->hasST4Port;
291  capability.hasBayer = cap->hasBayer;
292 }
293 
295 {
296  DefaultDevice::initProperties(); // let the base class flesh in what it wants
297 
298  // CCD Temperature
299  IUFillNumber(&TemperatureN[0], "CCD_TEMPERATURE_VALUE", "Temperature (C)", "%5.2f", -50.0, 50.0, 0., 0.);
300  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "CCD_TEMPERATURE", "Temperature", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE);
301 
302  // PRIMARY CCD Init
303 
304  IUFillNumber(&PrimaryCCD.ImageFrameN[0],"X","Left ","%4.0f",0,1392.0,0,0);
305  IUFillNumber(&PrimaryCCD.ImageFrameN[1],"Y","Top","%4.0f",0,1040,0,0);
306  IUFillNumber(&PrimaryCCD.ImageFrameN[2],"WIDTH","Width","%4.0f",0,1392.0,0,1392.0);
307  IUFillNumber(&PrimaryCCD.ImageFrameN[3],"HEIGHT","Height","%4.0f",0,1392,0,1392.0);
308  IUFillNumberVector(&PrimaryCCD.ImageFrameNP,PrimaryCCD.ImageFrameN,4,getDeviceName(),"CCD_FRAME","Frame",IMAGE_SETTINGS_TAB,IP_RW,60,IPS_IDLE);
309 
310  IUFillSwitch(&PrimaryCCD.FrameTypeS[0],"FRAME_LIGHT","Light",ISS_ON);
311  IUFillSwitch(&PrimaryCCD.FrameTypeS[1],"FRAME_BIAS","Bias",ISS_OFF);
312  IUFillSwitch(&PrimaryCCD.FrameTypeS[2],"FRAME_DARK","Dark",ISS_OFF);
313  IUFillSwitch(&PrimaryCCD.FrameTypeS[3],"FRAME_FLAT","Flat",ISS_OFF);
314  IUFillSwitchVector(&PrimaryCCD.FrameTypeSP,PrimaryCCD.FrameTypeS,4,getDeviceName(),"CCD_FRAME_TYPE","Frame Type",IMAGE_SETTINGS_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE);
315 
316  IUFillNumber(&PrimaryCCD.ImageExposureN[0],"CCD_EXPOSURE_VALUE","Duration (s)","%5.2f",0.01,3600,1.0,1.0);
317  IUFillNumberVector(&PrimaryCCD.ImageExposureNP,PrimaryCCD.ImageExposureN,1,getDeviceName(),"CCD_EXPOSURE","Expose",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE);
318 
319  IUFillSwitch(&PrimaryCCD.AbortExposureS[0],"ABORT","Abort",ISS_OFF);
320  IUFillSwitchVector(&PrimaryCCD.AbortExposureSP,PrimaryCCD.AbortExposureS,1,getDeviceName(),"CCD_ABORT_EXPOSURE","Expose Abort",MAIN_CONTROL_TAB,IP_RW,ISR_ATMOST1,60,IPS_IDLE);
321 
322  IUFillNumber(&PrimaryCCD.ImageBinN[0],"HOR_BIN","X","%2.0f",1,4,1,1);
323  IUFillNumber(&PrimaryCCD.ImageBinN[1],"VER_BIN","Y","%2.0f",1,4,1,1);
324  IUFillNumberVector(&PrimaryCCD.ImageBinNP,PrimaryCCD.ImageBinN,2,getDeviceName(),"CCD_BINNING","Binning",IMAGE_SETTINGS_TAB,IP_RW,60,IPS_IDLE);
325 
326  IUFillNumber(&PrimaryCCD.ImagePixelSizeN[0],"CCD_MAX_X","Resolution x","%4.0f",1,16000,0,1392.0);
327  IUFillNumber(&PrimaryCCD.ImagePixelSizeN[1],"CCD_MAX_Y","Resolution y","%4.0f",1,16000,0,1392.0);
328  IUFillNumber(&PrimaryCCD.ImagePixelSizeN[2],"CCD_PIXEL_SIZE","Pixel size (um)","%5.2f",1,40,0,6.45);
329  IUFillNumber(&PrimaryCCD.ImagePixelSizeN[3],"CCD_PIXEL_SIZE_X","Pixel size X","%5.2f",1,40,0,6.45);
330  IUFillNumber(&PrimaryCCD.ImagePixelSizeN[4],"CCD_PIXEL_SIZE_Y","Pixel size Y","%5.2f",1,40,0,6.45);
331  IUFillNumber(&PrimaryCCD.ImagePixelSizeN[5],"CCD_BITSPERPIXEL","Bits per pixel","%3.0f",8,64,0,8);
332  IUFillNumberVector(&PrimaryCCD.ImagePixelSizeNP,PrimaryCCD.ImagePixelSizeN,6,getDeviceName(),"CCD_INFO","CCD Information",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE);
333 
334  IUFillSwitch(&PrimaryCCD.CompressS[0],"CCD_COMPRESS","Compress",ISS_OFF);
335  IUFillSwitch(&PrimaryCCD.CompressS[1],"CCD_RAW","Raw",ISS_ON);
336  IUFillSwitchVector(&PrimaryCCD.CompressSP,PrimaryCCD.CompressS,2,getDeviceName(),"CCD_COMPRESSION","Image",IMAGE_SETTINGS_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE);
337  PrimaryCCD.SendCompressed = false;
338 
339  IUFillBLOB(&PrimaryCCD.FitsB,"CCD1","Image","");
340  IUFillBLOBVector(&PrimaryCCD.FitsBP,&PrimaryCCD.FitsB,1,getDeviceName(),"CCD1","Image Data",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE);
341 
342  IUFillSwitch(&PrimaryCCD.RapidGuideS[0], "ENABLE", "Enable", ISS_OFF);
343  IUFillSwitch(&PrimaryCCD.RapidGuideS[1], "DISABLE", "Disable", ISS_ON);
344  IUFillSwitchVector(&PrimaryCCD.RapidGuideSP, PrimaryCCD.RapidGuideS, 2, getDeviceName(), "CCD_RAPID_GUIDE", "Rapid Guide", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
345 
346  IUFillSwitch(&PrimaryCCD.RapidGuideSetupS[0], "AUTO_LOOP", "Auto loop", ISS_ON);
347  IUFillSwitch(&PrimaryCCD.RapidGuideSetupS[1], "SEND_IMAGE", "Send image", ISS_OFF);
348  IUFillSwitch(&PrimaryCCD.RapidGuideSetupS[2], "SHOW_MARKER", "Show marker", ISS_OFF);
349  IUFillSwitchVector(&PrimaryCCD.RapidGuideSetupSP, PrimaryCCD.RapidGuideSetupS, 3, getDeviceName(), "CCD_RAPID_GUIDE_SETUP", "Rapid Guide Setup", RAPIDGUIDE_TAB, IP_RW, ISR_NOFMANY, 0, IPS_IDLE);
350 
351  IUFillNumber(&PrimaryCCD.RapidGuideDataN[0],"GUIDESTAR_X","Guide star position X","%5.2f",0,1024,0,0);
352  IUFillNumber(&PrimaryCCD.RapidGuideDataN[1],"GUIDESTAR_Y","Guide star position Y","%5.2f",0,1024,0,0);
353  IUFillNumber(&PrimaryCCD.RapidGuideDataN[2],"GUIDESTAR_FIT","Guide star fit","%5.2f",0,1024,0,0);
354  IUFillNumberVector(&PrimaryCCD.RapidGuideDataNP,PrimaryCCD.RapidGuideDataN,3,getDeviceName(),"CCD_RAPID_GUIDE_DATA","Rapid Guide Data",RAPIDGUIDE_TAB,IP_RO,60,IPS_IDLE);
355 
356  // Reset Frame Settings
357  IUFillSwitch(&PrimaryCCD.ResetS[0], "RESET", "Reset", ISS_OFF);
358  IUFillSwitchVector(&PrimaryCCD.ResetSP, PrimaryCCD.ResetS, 1, getDeviceName(), "CCD_FRAME_RESET", "Frame Values", IMAGE_SETTINGS_TAB, IP_WO, ISR_1OFMANY, 0, IPS_IDLE);
359 
360  // GUIDER CCD Init
361 
362  IUFillNumber(&GuideCCD.ImageFrameN[0],"X","Left ","%4.0f",0,1392.0,0,0);
363  IUFillNumber(&GuideCCD.ImageFrameN[1],"Y","Top","%4.0f",0,1040,0,0);
364  IUFillNumber(&GuideCCD.ImageFrameN[2],"WIDTH","Width","%4.0f",0,1392.0,0,1392.0);
365  IUFillNumber(&GuideCCD.ImageFrameN[3],"HEIGHT","Height","%4.0f",0,1040,0,1040);
366  IUFillNumberVector(&GuideCCD.ImageFrameNP,GuideCCD.ImageFrameN,4,getDeviceName(),"GUIDER_FRAME","Frame",GUIDE_HEAD_TAB,IP_RW,60,IPS_IDLE);
367 
368  IUFillNumber(&GuideCCD.ImageBinN[0],"HOR_BIN","X","%2.0f",1,4,1,1);
369  IUFillNumber(&GuideCCD.ImageBinN[1],"VER_BIN","Y","%2.0f",1,4,1,1);
370  IUFillNumberVector(&GuideCCD.ImageBinNP,GuideCCD.ImageBinN,2,getDeviceName(),"GUIDER_BINNING","Binning",GUIDE_HEAD_TAB,IP_RW,60,IPS_IDLE);
371 
372  IUFillNumber(&GuideCCD.ImagePixelSizeN[0],"CCD_MAX_X","Resolution x","%4.0f",1,16000,0,1392.0);
373  IUFillNumber(&GuideCCD.ImagePixelSizeN[1],"CCD_MAX_Y","Resolution y","%4.0f",1,16000,0,1392.0);
374  IUFillNumber(&GuideCCD.ImagePixelSizeN[2],"CCD_PIXEL_SIZE","Pixel size (um)","%5.2f",1,40,0,6.45);
375  IUFillNumber(&GuideCCD.ImagePixelSizeN[3],"CCD_PIXEL_SIZE_X","Pixel size X","%5.2f",1,40,0,6.45);
376  IUFillNumber(&GuideCCD.ImagePixelSizeN[4],"CCD_PIXEL_SIZE_Y","Pixel size Y","%5.2f",1,40,0,6.45);
377  IUFillNumber(&GuideCCD.ImagePixelSizeN[5],"CCD_BITSPERPIXEL","Bits per pixel","%3.0f",8,64,0,8);
378  IUFillNumberVector(&GuideCCD.ImagePixelSizeNP,GuideCCD.ImagePixelSizeN,6,getDeviceName(),"GUIDER_INFO", "Guide Info",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE);
379 
380  IUFillSwitch(&GuideCCD.FrameTypeS[0],"FRAME_LIGHT","Light",ISS_ON);
381  IUFillSwitch(&GuideCCD.FrameTypeS[1],"FRAME_BIAS","Bias",ISS_OFF);
382  IUFillSwitch(&GuideCCD.FrameTypeS[2],"FRAME_DARK","Dark",ISS_OFF);
383  IUFillSwitch(&GuideCCD.FrameTypeS[3],"FRAME_FLAT","Flat",ISS_OFF);
384  IUFillSwitchVector(&GuideCCD.FrameTypeSP,GuideCCD.FrameTypeS,4,getDeviceName(),"GUIDER_FRAME_TYPE","Frame Type",GUIDE_HEAD_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE);
385 
386  IUFillNumber(&GuideCCD.ImageExposureN[0],"GUIDER_EXPOSURE_VALUE","Duration (s)","%5.2f",0.01,3600,1.0,1.0);
387  IUFillNumberVector(&GuideCCD.ImageExposureNP,GuideCCD.ImageExposureN,1,getDeviceName(),"GUIDER_EXPOSURE","Guide Head",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE);
388 
389  IUFillSwitch(&GuideCCD.AbortExposureS[0],"ABORT","Abort",ISS_OFF);
390  IUFillSwitchVector(&GuideCCD.AbortExposureSP,GuideCCD.AbortExposureS,1,getDeviceName(),"GUIDER_ABORT_EXPOSURE","Guide Abort",MAIN_CONTROL_TAB,IP_RW,ISR_ATMOST1,60,IPS_IDLE);
391 
392  IUFillSwitch(&GuideCCD.CompressS[0],"GUIDER_COMPRESS","Compress",ISS_OFF);
393  IUFillSwitch(&GuideCCD.CompressS[1],"GUIDER_RAW","Raw",ISS_ON);
394  IUFillSwitchVector(&GuideCCD.CompressSP,GuideCCD.CompressS,2,getDeviceName(),"GUIDER_COMPRESSION","Image",GUIDE_HEAD_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE);
395  GuideCCD.SendCompressed = false;
396 
397  IUFillBLOB(&GuideCCD.FitsB,"CCD2","Guider Image","");
398  IUFillBLOBVector(&GuideCCD.FitsBP,&GuideCCD.FitsB,1,getDeviceName(),"CCD2","Image Data",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE);
399 
400  IUFillSwitch(&GuideCCD.RapidGuideS[0], "ENABLE", "Enable", ISS_OFF);
401  IUFillSwitch(&GuideCCD.RapidGuideS[1], "DISABLE", "Disable", ISS_ON);
402  IUFillSwitchVector(&GuideCCD.RapidGuideSP, GuideCCD.RapidGuideS, 2, getDeviceName(), "GUIDER_RAPID_GUIDE", "Guider Head Rapid Guide", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
403 
404  IUFillSwitch(&GuideCCD.RapidGuideSetupS[0], "AUTO_LOOP", "Auto loop", ISS_ON);
405  IUFillSwitch(&GuideCCD.RapidGuideSetupS[1], "SEND_IMAGE", "Send image", ISS_OFF);
406  IUFillSwitch(&GuideCCD.RapidGuideSetupS[2], "SHOW_MARKER", "Show marker", ISS_OFF);
407  IUFillSwitchVector(&GuideCCD.RapidGuideSetupSP, GuideCCD.RapidGuideSetupS, 3, getDeviceName(), "GUIDER_RAPID_GUIDE_SETUP", "Rapid Guide Setup", RAPIDGUIDE_TAB, IP_RW, ISR_NOFMANY, 0, IPS_IDLE);
408 
409  IUFillNumber(&GuideCCD.RapidGuideDataN[0],"GUIDESTAR_X","Guide star position X","%5.2f",0,1024,0,0);
410  IUFillNumber(&GuideCCD.RapidGuideDataN[1],"GUIDESTAR_Y","Guide star position Y","%5.2f",0,1024,0,0);
411  IUFillNumber(&GuideCCD.RapidGuideDataN[2],"GUIDESTAR_FIT","Guide star fit","%5.2f",0,1024,0,0);
412  IUFillNumberVector(&GuideCCD.RapidGuideDataNP,GuideCCD.RapidGuideDataN,3,getDeviceName(),"GUIDER_RAPID_GUIDE_DATA","Rapid Guide Data",RAPIDGUIDE_TAB,IP_RO,60,IPS_IDLE);
413 
414  // CCD Class Init
415 
416  IUFillText(&BayerT[0],"CFA_OFFSET_X","X Offset","0");
417  IUFillText(&BayerT[1],"CFA_OFFSET_Y","Y Offset","0");
418  IUFillText(&BayerT[2],"CFA_TYPE","Filter",NULL);
419  IUFillTextVector(&BayerTP,BayerT,3,getDeviceName(),"CCD_CFA","Bayer Info",IMAGE_INFO_TAB,IP_RW,60,IPS_IDLE);
420 
421  IUFillSwitch(&UploadS[0], "UPLOAD_CLIENT", "Client", ISS_ON);
422  IUFillSwitch(&UploadS[1], "UPLOAD_LOCAL", "Local", ISS_OFF);
423  IUFillSwitch(&UploadS[2], "UPLOAD_BOTH", "Both", ISS_OFF);
424  IUFillSwitchVector(&UploadSP, UploadS, 3, getDeviceName(), "UPLOAD_MODE", "Upload", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
425 
426  IUFillText(&UploadSettingsT[0],"UPLOAD_DIR","Dir","");
427  IUFillText(&UploadSettingsT[1],"UPLOAD_PREFIX","Prefix","IMAGE_XXX");
428  IUFillTextVector(&UploadSettingsTP,UploadSettingsT,2,getDeviceName(),"UPLOAD_SETTINGS","Upload Settings",OPTIONS_TAB,IP_RW,60,IPS_IDLE);
429 
430  IUFillText(&ActiveDeviceT[0],"ACTIVE_TELESCOPE","Telescope","Telescope Simulator");
431  IUFillText(&ActiveDeviceT[1],"ACTIVE_FOCUSER","Focuser","Focuser Simulator");
432  IUFillText(&ActiveDeviceT[2],"ACTIVE_FILTER","Filter","CCD Simulator");
433  IUFillTextVector(&ActiveDeviceTP,ActiveDeviceT,3,getDeviceName(),"ACTIVE_DEVICES","Snoop devices",OPTIONS_TAB,IP_RW,60,IPS_IDLE);
434 
435  IUFillSwitch(&WorldCoordS[0], "WCS_ENABLE", "Enable", ISS_OFF);
436  IUFillSwitch(&WorldCoordS[1], "WCS_DISABLE", "Disable", ISS_ON);
437  IUFillSwitchVector(&WorldCoordSP, WorldCoordS, 2, getDeviceName(), "WCS_CONTROL", "WCS", WCS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
438 
439  IUFillSwitch(&TelescopeTypeS[0], "TELESCOPE_PRIMARY", "Primary", ISS_ON);
440  IUFillSwitch(&TelescopeTypeS[1], "TELESCOPE_GUIDE", "Guide", ISS_OFF);
441  IUFillSwitchVector(&TelescopeTypeSP, TelescopeTypeS, 2, getDeviceName(), "TELESCOPE_TYPE", "Telescope", WCS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
442 
443  IUFillNumber(&CCDRotationN[0],"CCD_ROTATION_VALUE","Rotation","%g",-360,360,1,0);
444  IUFillNumberVector(&CCDRotationNP,CCDRotationN,1,getDeviceName(),"CCD_ROTATION","CCD FOV", WCS_TAB,IP_RW,60,IPS_IDLE);
445 
446  IUFillNumber(&EqN[0],"RA","Ra (hh:mm:ss)","%010.6m",0,24,0,0);
447  IUFillNumber(&EqN[1],"DEC","Dec (dd:mm:ss)","%010.6m",-90,90,0,0);
448  IUFillNumberVector(&EqNP,EqN,2,ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD","EQ Coord","Main Control",IP_RW,60,IPS_IDLE);
449 
450  IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD");
451  IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO");
452  IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_SLOT");
453  IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_NAME");
454 
455  // Guider Interface
456  initGuiderProperties(getDeviceName(), GUIDE_CONTROL_TAB);
457 
458  setInterfaceDescriptor(CCD_INTERFACE|GUIDER_INTERFACE);
459 
460  return true;
461 }
462 
463 void INDI::CCD::ISGetProperties (const char *dev)
464 {
465  // First we let our parent populate
466 
467  //IDLog("INDI::CCD IsGetProperties with %s\n",dev);
468 
470 
471  return;
472 }
473 
475 {
476  //IDLog("INDI::CCD UpdateProperties isConnected returns %d %d\n",isConnected(),Connected);
477  if(isConnected())
478  {
479  defineNumber(&PrimaryCCD.ImageExposureNP);
480 
481  if (capability.canAbort)
482  defineSwitch(&PrimaryCCD.AbortExposureSP);
483  if (capability.canSubFrame == false)
484  PrimaryCCD.ImageFrameNP.p = IP_RO;
485 
486  defineNumber(&PrimaryCCD.ImageFrameNP);
487  if (capability.canBin)
488  defineNumber(&PrimaryCCD.ImageBinNP);
489 
490  if(capability.hasGuideHead)
491  {
492  defineNumber(&GuideCCD.ImageExposureNP);
493  if (capability.canAbort)
494  defineSwitch(&GuideCCD.AbortExposureSP);
495  if (capability.canSubFrame == false)
496  GuideCCD.ImageFrameNP.p = IP_RO;
497  defineNumber(&GuideCCD.ImageFrameNP);
498  }
499 
500  if (capability.hasCooler)
501  defineNumber(&TemperatureNP);
502 
503  defineNumber(&PrimaryCCD.ImagePixelSizeNP);
504  if(capability.hasGuideHead)
505  {
506  defineNumber(&GuideCCD.ImagePixelSizeNP);
507  if (capability.canBin)
508  defineNumber(&GuideCCD.ImageBinNP);
509  }
510  defineSwitch(&PrimaryCCD.CompressSP);
511  defineBLOB(&PrimaryCCD.FitsBP);
512  if(capability.hasGuideHead)
513  {
514  defineSwitch(&GuideCCD.CompressSP);
515  defineBLOB(&GuideCCD.FitsBP);
516  }
517  if(capability.hasST4Port)
518  {
519  defineNumber(&GuideNSNP);
520  defineNumber(&GuideWENP);
521  }
522  defineSwitch(&PrimaryCCD.FrameTypeSP);
523 
524  if (capability.canBin || capability.canSubFrame)
525  defineSwitch(&PrimaryCCD.ResetSP);
526 
527  if (capability.hasGuideHead)
528  defineSwitch(&GuideCCD.FrameTypeSP);
529 
530  if (capability.hasBayer)
531  defineText(&BayerTP);
532 
533  defineSwitch(&PrimaryCCD.RapidGuideSP);
534 
535  if (capability.hasGuideHead)
536  defineSwitch(&GuideCCD.RapidGuideSP);
537 
538  if (RapidGuideEnabled)
539  {
540  defineSwitch(&PrimaryCCD.RapidGuideSetupSP);
541  defineNumber(&PrimaryCCD.RapidGuideDataNP);
542  }
543  if (GuiderRapidGuideEnabled)
544  {
545  defineSwitch(&GuideCCD.RapidGuideSetupSP);
546  defineNumber(&GuideCCD.RapidGuideDataNP);
547  }
548  defineText(&ActiveDeviceTP);
549  defineSwitch(&WorldCoordSP);
550  defineSwitch(&UploadSP);
551 
552  if (UploadSettingsT[0].text == NULL)
553  IUSaveText(&UploadSettingsT[0], getenv("HOME"));
554  defineText(&UploadSettingsTP);
555  }
556  else
557  {
558  deleteProperty(PrimaryCCD.ImageFrameNP.name);
559  deleteProperty(PrimaryCCD.ImagePixelSizeNP.name);
560 
561  if (capability.canBin)
562  deleteProperty(PrimaryCCD.ImageBinNP.name);
563 
564  deleteProperty(PrimaryCCD.ImageExposureNP.name);
565  if (capability.canAbort)
566  deleteProperty(PrimaryCCD.AbortExposureSP.name);
567  deleteProperty(PrimaryCCD.FitsBP.name);
568  deleteProperty(PrimaryCCD.CompressSP.name);
569  deleteProperty(PrimaryCCD.RapidGuideSP.name);
570  if (RapidGuideEnabled)
571  {
572  deleteProperty(PrimaryCCD.RapidGuideSetupSP.name);
573  deleteProperty(PrimaryCCD.RapidGuideDataNP.name);
574  }
575  if(capability.hasGuideHead)
576  {
577  deleteProperty(GuideCCD.ImageExposureNP.name);
578  if (capability.canAbort)
579  deleteProperty(GuideCCD.AbortExposureSP.name);
580  deleteProperty(GuideCCD.ImageFrameNP.name);
581  deleteProperty(GuideCCD.ImagePixelSizeNP.name);
582 
583  deleteProperty(GuideCCD.FitsBP.name);
584  if (capability.canBin)
585  deleteProperty(GuideCCD.ImageBinNP.name);
586  deleteProperty(GuideCCD.CompressSP.name);
587  deleteProperty(GuideCCD.FrameTypeSP.name);
588  deleteProperty(GuideCCD.RapidGuideSP.name);
589  if (GuiderRapidGuideEnabled)
590  {
591  deleteProperty(GuideCCD.RapidGuideSetupSP.name);
592  deleteProperty(GuideCCD.RapidGuideDataNP.name);
593  }
594  }
595  if (capability.hasCooler)
596  deleteProperty(TemperatureNP.name);
597  if(capability.hasST4Port)
598  {
599  deleteProperty(GuideNSNP.name);
600  deleteProperty(GuideWENP.name);
601  }
602  deleteProperty(PrimaryCCD.FrameTypeSP.name);
603  if (capability.canBin || capability.canSubFrame)
604  deleteProperty(PrimaryCCD.ResetSP.name);
605  if (capability.hasBayer)
606  deleteProperty(BayerTP.name);
607  deleteProperty(ActiveDeviceTP.name);
608  if (WorldCoordS[0].s == ISS_ON)
609  {
610  deleteProperty(TelescopeTypeSP.name);
611  deleteProperty(CCDRotationNP.name);
612  }
613  deleteProperty(WorldCoordSP.name);
614  deleteProperty(UploadSP.name);
615  deleteProperty(UploadSettingsTP.name);
616  }
617  return true;
618 }
619 
620 bool INDI::CCD::ISSnoopDevice (XMLEle *root)
621 {
622  XMLEle *ep=NULL;
623  const char *propName = findXMLAttValu(root, "name");
624 
625  if(IUSnoopNumber(root,&EqNP)==0)
626  {
627  float newra,newdec;
628  newra=EqN[0].value;
629  newdec=EqN[1].value;
630  if((newra != RA)||(newdec != Dec))
631  {
632  //IDLog("RA %4.2f Dec %4.2f Snooped RA %4.2f Dec %4.2f\n",RA,Dec,newra,newdec);
633  RA=newra;
634  Dec=newdec;
635  }
636  }
637  else if (!strcmp(propName, "TELESCOPE_INFO"))
638  {
639  for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0))
640  {
641  const char *name = findXMLAttValu(ep, "name");
642 
643  if (!strcmp(name, "TELESCOPE_APERTURE"))
644  {
645  if (TelescopeTypeS[0].s == ISS_ON)
646  Aperture = atof(pcdataXMLEle(ep));
647  }
648  else if (!strcmp(name, "TELESCOPE_FOCAL_LENGTH"))
649  {
650  if (TelescopeTypeS[0].s == ISS_ON)
651  FocalLength = atof(pcdataXMLEle(ep));
652  }
653  else if (!strcmp(name, "GUIDER_APERTURE"))
654  {
655  if (TelescopeTypeS[1].s == ISS_ON)
656  Aperture = atof(pcdataXMLEle(ep));
657  }
658  else if (!strcmp(name, "GUIDER_FOCAL_LENGTH"))
659  {
660  if (TelescopeTypeS[1].s == ISS_ON)
661  FocalLength = atof(pcdataXMLEle(ep));
662  }
663  }
664  }
665  else if (!strcmp(propName, "FILTER_NAME"))
666  {
667  FilterNames.clear();
668 
669  for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0))
670  FilterNames.push_back(pcdataXMLEle(ep));
671  }
672  else if (!strcmp(propName, "FILTER_SLOT"))
673  {
674  CurrentFilterSlot=-1;
675  for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0))
676  CurrentFilterSlot = atoi(pcdataXMLEle(ep));
677  }
678 
680  }
681 
682 bool INDI::CCD::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
683 {
684  // first check if it's for our device
685  if(strcmp(dev,getDeviceName())==0)
686  {
687  // This is for our device
688  // Now lets see if it's something we process here
689  if(!strcmp(name,ActiveDeviceTP.name))
690  {
691  int rc;
692  ActiveDeviceTP.s=IPS_OK;
693  rc=IUUpdateText(&ActiveDeviceTP,texts,names,n);
694  // Update client display
695  IDSetText(&ActiveDeviceTP,NULL);
696  //saveConfig();
697 
698  // Update the property name!
699  strncpy(EqNP.device, ActiveDeviceT[0].text, MAXINDIDEVICE);
700  IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD");
701  IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO");
702  IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_SLOT");
703  IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_NAME");
704 
705  // Tell children active devices was updated.
706  activeDevicesUpdated();
707 
708  // We processed this one, so, tell the world we did it
709  return true;
710  }
711 
712  if (!strcmp(name, BayerTP.name))
713  {
714  IUUpdateText(&BayerTP, texts, names, n);
715  BayerTP.s = IPS_OK;
716  IDSetText(&BayerTP, NULL);
717  return true;
718  }
719 
720  if (!strcmp(name, UploadSettingsTP.name))
721  {
722  IUUpdateText(&UploadSettingsTP, texts, names, n);
723  IDSetText(&UploadSettingsTP, NULL);
724  return true;
725  }
726 
727  }
728 
729  return INDI::DefaultDevice::ISNewText(dev,name,texts,names,n);
730 }
731 
732 bool INDI::CCD::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
733 {
734  // first check if it's for our device
735  //IDLog("INDI::CCD::ISNewNumber %s\n",name);
736  if(strcmp(dev,getDeviceName())==0)
737  {
738  // This is for our device
739  // Now lets see if it's something we process here
740  if(strcmp(name,"CCD_EXPOSURE")==0)
741  {
742  if (values[0] < PrimaryCCD.ImageExposureN[0].min || values[0] > PrimaryCCD.ImageExposureN[0].max)
743  {
744  DEBUGF(INDI::Logger::DBG_ERROR, "Requested exposure value (%g) seconds out of bounds [%g,%g].", values[0], PrimaryCCD.ImageExposureN[0].min, PrimaryCCD.ImageExposureN[0].max);
745  PrimaryCCD.ImageExposureNP.s=IPS_ALERT;
746  IDSetNumber(&PrimaryCCD.ImageExposureNP,NULL);
747  return false;
748  }
749 
750  PrimaryCCD.ImageExposureN[0].value = ExposureTime = values[0];
751 
752  if (PrimaryCCD.ImageExposureNP.s==IPS_BUSY)
753  AbortExposure();
754 
755  if (StartExposure(ExposureTime))
756  PrimaryCCD.ImageExposureNP.s=IPS_BUSY;
757  else
758  PrimaryCCD.ImageExposureNP.s=IPS_ALERT;
759  IDSetNumber(&PrimaryCCD.ImageExposureNP,NULL);
760  return true;
761  }
762 
763  if(strcmp(name,"GUIDER_EXPOSURE")==0)
764  {
765  if (values[0] < GuideCCD.ImageExposureN[0].min || values[0] > GuideCCD.ImageExposureN[0].max)
766  {
767  DEBUGF(INDI::Logger::DBG_ERROR, "Requested guide exposure value (%g) seconds out of bounds [%g,%g].", values[0], GuideCCD.ImageExposureN[0].min, GuideCCD.ImageExposureN[0].max);
768  GuideCCD.ImageExposureNP.s=IPS_ALERT;
769  IDSetNumber(&GuideCCD.ImageExposureNP,NULL);
770  return false;
771  }
772 
773  GuideCCD.ImageExposureN[0].value = GuiderExposureTime = values[0];
774  GuideCCD.ImageExposureNP.s=IPS_BUSY;
775  if (StartGuideExposure(GuiderExposureTime))
776  GuideCCD.ImageExposureNP.s=IPS_BUSY;
777  else
778  GuideCCD.ImageExposureNP.s=IPS_ALERT;
779  IDSetNumber(&GuideCCD.ImageExposureNP,NULL);
780  return true;
781  }
782 
783  if(strcmp(name,"CCD_BINNING")==0)
784  {
785  // We are being asked to set camera binning
786  INumber *np = IUFindNumber(&PrimaryCCD.ImageBinNP, names[0]);
787  if (np == NULL)
788  {
789  PrimaryCCD.ImageBinNP.s = IPS_ALERT;
790  IDSetNumber (&PrimaryCCD.ImageBinNP, NULL);
791  return false;
792  }
793 
794  int binx,biny;
795  if (!strcmp(np->name, "HOR_BIN"))
796  {
797  binx = values[0];
798  biny = values[1];
799  }
800  else
801  {
802  binx = values[1];
803  biny = values[0];
804  }
805 
806  if (UpdateCCDBin(binx, biny))
807  {
808  IUUpdateNumber(&PrimaryCCD.ImageBinNP,values,names,n);
809  PrimaryCCD.ImageBinNP.s=IPS_OK;
810 
811  }
812  else
813  PrimaryCCD.ImageBinNP.s = IPS_ALERT;
814 
815  IDSetNumber (&PrimaryCCD.ImageBinNP, NULL);
816 
817  return true;
818 
819  }
820 
821  if(strcmp(name,"GUIDER_BINNING")==0)
822  {
823  // We are being asked to set camera binning
824  INumber *np = IUFindNumber(&GuideCCD.ImageBinNP, names[0]);
825  if (np == NULL)
826  {
827  GuideCCD.ImageBinNP.s = IPS_ALERT;
828  IDSetNumber (&GuideCCD.ImageBinNP, NULL);
829  return false;
830  }
831 
832  int binx,biny;
833  if (!strcmp(np->name, "HOR_BIN"))
834  {
835  binx = values[0];
836  biny = values[1];
837  }
838  else
839  {
840  binx = values[1];
841  biny = values[0];
842  }
843 
844  if (UpdateGuiderBin(binx, biny))
845  {
846  IUUpdateNumber(&GuideCCD.ImageBinNP,values,names,n);
847  GuideCCD.ImageBinNP.s=IPS_OK;
848 
849  }
850  else
851  GuideCCD.ImageBinNP.s = IPS_ALERT;
852 
853  IDSetNumber (&GuideCCD.ImageBinNP, NULL);
854 
855  return true;
856 
857 
858  }
859 
860  if(strcmp(name,"CCD_FRAME")==0)
861  {
862  // We are being asked to set CCD Frame
863  if (IUUpdateNumber(&PrimaryCCD.ImageFrameNP,values,names,n) < 0)
864  return false;
865 
866  PrimaryCCD.ImageFrameNP.s=IPS_OK;
867 
868  DEBUGF(Logger::DBG_DEBUG, "Requested CCD Frame is (%3.0f,%3.0f) (%3.0f x %3.0f)", values[0],values[1],values[2],values[3]);
869 
870  if (UpdateCCDFrame(PrimaryCCD.ImageFrameN[0].value, PrimaryCCD.ImageFrameN[1].value, PrimaryCCD.ImageFrameN[2].value,
871  PrimaryCCD.ImageFrameN[3].value) == false)
872  PrimaryCCD.ImageFrameNP.s = IPS_ALERT;
873 
874  IDSetNumber(&PrimaryCCD.ImageFrameNP, NULL);
875  return true;
876  }
877 
878  if(strcmp(name,"GUIDER_FRAME")==0)
879  {
880  // We are being asked to set guide frame
881  if (IUUpdateNumber(&GuideCCD.ImageFrameNP,values,names,n) < 0)
882  return false;
883 
884  GuideCCD.ImageFrameNP.s=IPS_OK;
885 
886  DEBUGF(Logger::DBG_DEBUG, "Requested Guide Frame is %4.0f,%4.0f %4.0f x %4.0f",
887  values[0],values[1],values[2],values[4]);
888 
889  if (UpdateGuiderFrame(GuideCCD.ImageFrameN[0].value, GuideCCD.ImageFrameN[1].value, GuideCCD.ImageFrameN[2].value,
890  GuideCCD.ImageFrameN[3].value) == false)
891  GuideCCD.ImageFrameNP.s = IPS_ALERT;
892 
893  IDSetNumber(&GuideCCD.ImageFrameNP, NULL);
894 
895  return true;
896  }
897 
898  if(strcmp(name,"CCD_GUIDESTAR")==0)
899  {
900  PrimaryCCD.RapidGuideDataNP.s=IPS_OK;
901  IUUpdateNumber(&PrimaryCCD.RapidGuideDataNP,values,names,n);
902  IDSetNumber(&PrimaryCCD.RapidGuideDataNP, NULL);
903  return true;
904  }
905 
906  if(strcmp(name,"GUIDER_GUIDESTAR")==0)
907  {
908  GuideCCD.RapidGuideDataNP.s=IPS_OK;
909  IUUpdateNumber(&GuideCCD.RapidGuideDataNP,values,names,n);
910  IDSetNumber(&GuideCCD.RapidGuideDataNP, NULL);
911  return true;
912  }
913 
914  if (!strcmp(name,GuideNSNP.name) || !strcmp(name,GuideWENP.name))
915  {
916  processGuiderProperties(name, values, names, n);
917  return true;
918  }
919 
920  // CCD TEMPERATURE:
921  if(!strcmp(name, TemperatureNP.name))
922  {
923 
924  if(values[0] < TemperatureN[0].min || values[0] > TemperatureN[0].max)
925  {
926  TemperatureNP.s = IPS_ALERT;
927  DEBUGF(INDI::Logger::DBG_ERROR, "Error: Bad temperature value! Range is [%.1f, %.1f] [C].",
928  TemperatureN[0].min, TemperatureN[0].max);
929  IDSetNumber(&TemperatureNP, NULL);
930  return false;
931 
932  }
933 
934  int rc= SetTemperature(values[0]);
935 
936  if (rc == 0)
937  TemperatureNP.s = IPS_BUSY;
938  else if (rc == 1)
939  TemperatureNP.s = IPS_OK;
940  else
941  TemperatureNP.s = IPS_ALERT;
942 
943  IDSetNumber(&TemperatureNP, NULL);
944  return true;
945  }
946 
947  // Primary CCD Info
948  if (!strcmp(name, PrimaryCCD.ImagePixelSizeNP.name))
949  {
950  IUUpdateNumber(&PrimaryCCD.ImagePixelSizeNP, values, names, n);
951  PrimaryCCD.ImagePixelSizeNP.s = IPS_OK;
952  SetCCDParams(PrimaryCCD.ImagePixelSizeNP.np[0].value, PrimaryCCD.ImagePixelSizeNP.np[1].value, PrimaryCCD.getBPP(), PrimaryCCD.ImagePixelSizeNP.np[2].value, PrimaryCCD.ImagePixelSizeNP.np[3].value);
953  IDSetNumber(&PrimaryCCD.ImagePixelSizeNP, NULL);
954  return true;
955  }
956 
957  // Guide CCD Info
958  if (!strcmp(name, GuideCCD.ImagePixelSizeNP.name))
959  {
960  IUUpdateNumber(&GuideCCD.ImagePixelSizeNP, values, names, n);
961  GuideCCD.ImagePixelSizeNP.s = IPS_OK;
962  SetGuiderParams(GuideCCD.ImagePixelSizeNP.np[0].value, GuideCCD.ImagePixelSizeNP.np[1].value, GuideCCD.getBPP(), GuideCCD.ImagePixelSizeNP.np[2].value, GuideCCD.ImagePixelSizeNP.np[3].value);
963  IDSetNumber(&GuideCCD.ImagePixelSizeNP, NULL);
964  return true;
965  }
966 
967  // CCD Rotation
968  if (!strcmp(name, CCDRotationNP.name))
969  {
970  IUUpdateNumber(&CCDRotationNP, values, names, n);
971  CCDRotationNP.s = IPS_OK;
972  IDSetNumber(&CCDRotationNP, NULL);
973  ValidCCDRotation=true;
974 
975  DEBUGF(INDI::Logger::DBG_SESSION, "CCD FOV rotation updated to %g degrees.", CCDRotationN[0].value);
976 
977  return true;
978  }
979  }
980  // if we didn't process it, continue up the chain, let somebody else
981  // give it a shot
982  return DefaultDevice::ISNewNumber(dev,name,values,names,n);
983 }
984 
985 bool INDI::CCD::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
986 {
987 
988  if(strcmp(dev,getDeviceName())==0)
989  {
990  if (!strcmp(name, UploadSP.name))
991  {
992  IUUpdateSwitch(&UploadSP, states, names, n);
993  UploadSP.s = IPS_OK;
994  IDSetSwitch(&UploadSP, NULL);
995 
996  if (UploadS[0].s == ISS_ON)
997  DEBUG(INDI::Logger::DBG_SESSION, "Upload settings set to client only.");
998  else if (UploadS[1].s == ISS_ON)
999  DEBUG(INDI::Logger::DBG_SESSION, "Upload settings set to local only.");
1000  else
1001  DEBUG(INDI::Logger::DBG_SESSION, "Upload settings set to client and local.");
1002  return true;
1003  }
1004 
1005  if (!strcmp(name, TelescopeTypeSP.name))
1006  {
1007  IUUpdateSwitch(&TelescopeTypeSP, states, names, n);
1008  TelescopeTypeSP.s = IPS_OK;
1009  IDSetSwitch(&TelescopeTypeSP, NULL);
1010  return true;
1011  }
1012 
1013  if (!strcmp(name, WorldCoordSP.name))
1014  {
1015  IUUpdateSwitch(&WorldCoordSP, states, names, n);
1016  WorldCoordSP.s = IPS_OK;
1017 
1018  if (WorldCoordS[0].s == ISS_ON)
1019  {
1020  DEBUG(INDI::Logger::DBG_WARNING, "World Coordinate System is enabled. CCD rotation must be set either manually or by solving the image before proceeding to capture any frames, otherwise the WCS information may be invalid.");
1021  defineSwitch(&TelescopeTypeSP);
1022  defineNumber(&CCDRotationNP);
1023  }
1024  else
1025  {
1026  deleteProperty(TelescopeTypeSP.name);
1027  deleteProperty(CCDRotationNP.name);
1028  }
1029 
1030  ValidCCDRotation=false;
1031  IDSetSwitch(&WorldCoordSP, NULL);
1032  }
1033 
1034  // Reset
1035  if(strcmp(name,PrimaryCCD.ResetSP.name)==0)
1036  {
1037  IUResetSwitch(&PrimaryCCD.ResetSP);
1038  PrimaryCCD.ResetSP.s = IPS_OK;
1039  if (capability.canBin)
1040  UpdateCCDBin(1,1);
1041  if (capability.canSubFrame)
1042  UpdateCCDFrame(0,0, PrimaryCCD.getXRes(), PrimaryCCD.getYRes());
1043 
1044  IDSetSwitch(&PrimaryCCD.ResetSP, NULL);
1045  return true;
1046  }
1047 
1048  if(strcmp(name,PrimaryCCD.AbortExposureSP.name)==0)
1049  {
1050  IUResetSwitch(&PrimaryCCD.AbortExposureSP);
1051 
1052  if (AbortExposure())
1053  {
1054  PrimaryCCD.AbortExposureSP.s = IPS_OK;
1055  PrimaryCCD.ImageExposureNP.s = IPS_IDLE;
1056  PrimaryCCD.ImageExposureN[0].value = 0;
1057  }
1058  else
1059  {
1060  PrimaryCCD.AbortExposureSP.s = IPS_ALERT;
1061  PrimaryCCD.ImageExposureNP.s = IPS_ALERT;
1062  }
1063 
1064  IDSetSwitch(&PrimaryCCD.AbortExposureSP, NULL);
1065  IDSetNumber(&PrimaryCCD.ImageExposureNP, NULL);
1066 
1067  return true;
1068  }
1069 
1070  if(strcmp(name,GuideCCD.AbortExposureSP.name)==0)
1071  {
1072  IUResetSwitch(&GuideCCD.AbortExposureSP);
1073 
1074  if (AbortGuideExposure())
1075  {
1076  GuideCCD.AbortExposureSP.s = IPS_OK;
1077  GuideCCD.ImageExposureNP.s = IPS_IDLE;
1078  GuideCCD.ImageExposureN[0].value = 0;
1079  }
1080  else
1081  {
1082  GuideCCD.AbortExposureSP.s = IPS_ALERT;
1083  GuideCCD.ImageExposureNP.s = IPS_ALERT;
1084  }
1085 
1086  IDSetSwitch(&GuideCCD.AbortExposureSP, NULL);
1087  IDSetNumber(&GuideCCD.ImageExposureNP, NULL);
1088 
1089  return true;
1090  }
1091 
1092  if(strcmp(name,PrimaryCCD.CompressSP.name)==0)
1093  {
1094 
1095  IUUpdateSwitch(&PrimaryCCD.CompressSP,states,names,n);
1096  PrimaryCCD.CompressSP.s = IPS_OK;
1097  IDSetSwitch(&PrimaryCCD.CompressSP,NULL);
1098 
1099  if(PrimaryCCD.CompressS[0].s==ISS_ON )
1100  {
1101  PrimaryCCD.SendCompressed=true;
1102  } else
1103  {
1104  PrimaryCCD.SendCompressed=false;
1105  }
1106  return true;
1107  }
1108 
1109  if(strcmp(name,GuideCCD.CompressSP.name)==0)
1110  {
1111 
1112  IUUpdateSwitch(&GuideCCD.CompressSP,states,names,n);
1113  GuideCCD.CompressSP.s = IPS_OK;
1114  IDSetSwitch(&GuideCCD.CompressSP,NULL);
1115 
1116  if(GuideCCD.CompressS[0].s==ISS_ON )
1117  {
1118  GuideCCD.SendCompressed=true;
1119  } else
1120  {
1121  GuideCCD.SendCompressed=false;
1122  }
1123  return true;
1124  }
1125 
1126  if(strcmp(name,PrimaryCCD.FrameTypeSP.name)==0)
1127  {
1128  IUUpdateSwitch(&PrimaryCCD.FrameTypeSP,states,names,n);
1129  PrimaryCCD.FrameTypeSP.s=IPS_OK;
1130  if(PrimaryCCD.FrameTypeS[0].s==ISS_ON)
1131  PrimaryCCD.setFrameType(CCDChip::LIGHT_FRAME);
1132  else if(PrimaryCCD.FrameTypeS[1].s==ISS_ON)
1133  {
1134  PrimaryCCD.setFrameType(CCDChip::BIAS_FRAME);
1135  if (capability.hasShutter == false)
1136  DEBUG(INDI::Logger::DBG_WARNING, "The CCD does not have a shutter. Cover the camera in order to take a bias frame.");
1137  }
1138  else if(PrimaryCCD.FrameTypeS[2].s==ISS_ON)
1139  {
1140  PrimaryCCD.setFrameType(CCDChip::DARK_FRAME);
1141  if (capability.hasShutter == false)
1142  DEBUG(INDI::Logger::DBG_WARNING, "The CCD does not have a shutter. Cover the camera in order to take a dark frame.");
1143  }
1144  else if(PrimaryCCD.FrameTypeS[3].s==ISS_ON)
1145  PrimaryCCD.setFrameType(CCDChip::FLAT_FRAME);
1146 
1147  if (UpdateCCDFrameType(PrimaryCCD.getFrameType()) == false)
1148  PrimaryCCD.FrameTypeSP.s = IPS_ALERT;
1149 
1150  IDSetSwitch(&PrimaryCCD.FrameTypeSP,NULL);
1151 
1152  return true;
1153  }
1154 
1155  if(strcmp(name,GuideCCD.FrameTypeSP.name)==0)
1156  {
1157  // Compression Update
1158  IUUpdateSwitch(&GuideCCD.FrameTypeSP,states,names,n);
1159  GuideCCD.FrameTypeSP.s=IPS_OK;
1160  if(GuideCCD.FrameTypeS[0].s==ISS_ON)
1161  GuideCCD.setFrameType(CCDChip::LIGHT_FRAME);
1162  else if(GuideCCD.FrameTypeS[1].s==ISS_ON)
1163  {
1164  GuideCCD.setFrameType(CCDChip::BIAS_FRAME);
1165  if (capability.hasShutter == false)
1166  DEBUG(INDI::Logger::DBG_WARNING, "The CCD does not have a shutter. Cover the camera in order to take a bias frame.");
1167  }
1168  else if(GuideCCD.FrameTypeS[2].s==ISS_ON)
1169  {
1170  GuideCCD.setFrameType(CCDChip::DARK_FRAME);
1171  if (capability.hasShutter == false)
1172  DEBUG(INDI::Logger::DBG_WARNING, "The CCD does not have a shutter. Cover the camera in order to take a dark frame.");
1173  }
1174  else if(GuideCCD.FrameTypeS[3].s==ISS_ON)
1175  GuideCCD.setFrameType(CCDChip::FLAT_FRAME);
1176 
1177  if (UpdateGuiderFrameType(GuideCCD.getFrameType()) == false)
1178  GuideCCD.FrameTypeSP.s = IPS_ALERT;
1179 
1180  IDSetSwitch(&GuideCCD.FrameTypeSP,NULL);
1181 
1182  return true;
1183  }
1184 
1185 
1186  if (strcmp(name, PrimaryCCD.RapidGuideSP.name)==0)
1187  {
1188  IUUpdateSwitch(&PrimaryCCD.RapidGuideSP, states, names, n);
1189  PrimaryCCD.RapidGuideSP.s=IPS_OK;
1190  RapidGuideEnabled=(PrimaryCCD.RapidGuideS[0].s==ISS_ON);
1191 
1192  if (RapidGuideEnabled) {
1193  defineSwitch(&PrimaryCCD.RapidGuideSetupSP);
1194  defineNumber(&PrimaryCCD.RapidGuideDataNP);
1195  }
1196  else {
1197  deleteProperty(PrimaryCCD.RapidGuideSetupSP.name);
1198  deleteProperty(PrimaryCCD.RapidGuideDataNP.name);
1199  }
1200 
1201  IDSetSwitch(&PrimaryCCD.RapidGuideSP,NULL);
1202  return true;
1203  }
1204 
1205  if (strcmp(name, GuideCCD.RapidGuideSP.name)==0)
1206  {
1207  IUUpdateSwitch(&GuideCCD.RapidGuideSP, states, names, n);
1208  GuideCCD.RapidGuideSP.s=IPS_OK;
1209  GuiderRapidGuideEnabled=(GuideCCD.RapidGuideS[0].s==ISS_ON);
1210 
1211  if (GuiderRapidGuideEnabled) {
1212  defineSwitch(&GuideCCD.RapidGuideSetupSP);
1213  defineNumber(&GuideCCD.RapidGuideDataNP);
1214  }
1215  else {
1216  deleteProperty(GuideCCD.RapidGuideSetupSP.name);
1217  deleteProperty(GuideCCD.RapidGuideDataNP.name);
1218  }
1219 
1220  IDSetSwitch(&GuideCCD.RapidGuideSP,NULL);
1221  return true;
1222  }
1223 
1224  if (strcmp(name, PrimaryCCD.RapidGuideSetupSP.name)==0)
1225  {
1226  IUUpdateSwitch(&PrimaryCCD.RapidGuideSetupSP, states, names, n);
1227  PrimaryCCD.RapidGuideSetupSP.s=IPS_OK;
1228 
1229  AutoLoop=(PrimaryCCD.RapidGuideSetupS[0].s==ISS_ON);
1230  SendImage=(PrimaryCCD.RapidGuideSetupS[1].s==ISS_ON);
1231  ShowMarker=(PrimaryCCD.RapidGuideSetupS[2].s==ISS_ON);
1232 
1233  IDSetSwitch(&PrimaryCCD.RapidGuideSetupSP,NULL);
1234  return true;
1235  }
1236 
1237  if (strcmp(name, GuideCCD.RapidGuideSetupSP.name)==0)
1238  {
1239  IUUpdateSwitch(&GuideCCD.RapidGuideSetupSP, states, names, n);
1240  GuideCCD.RapidGuideSetupSP.s=IPS_OK;
1241 
1242  GuiderAutoLoop=(GuideCCD.RapidGuideSetupS[0].s==ISS_ON);
1243  GuiderSendImage=(GuideCCD.RapidGuideSetupS[1].s==ISS_ON);
1244  GuiderShowMarker=(GuideCCD.RapidGuideSetupS[2].s==ISS_ON);
1245 
1246  IDSetSwitch(&GuideCCD.RapidGuideSetupSP,NULL);
1247  return true;
1248  }
1249  }
1250 
1251  // let the default driver have a crack at it
1252  return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
1253 }
1254 
1255 int INDI::CCD::SetTemperature(double temperature)
1256 {
1257  INDI_UNUSED(temperature);
1258  DEBUGF(INDI::Logger::DBG_WARNING, "INDI::CCD::SetTemperature %4.2f - Should never get here", temperature);
1259  return -1;
1260 }
1261 
1262 bool INDI::CCD::StartExposure(float duration)
1263 {
1264  DEBUGF(INDI::Logger::DBG_WARNING, "INDI::CCD::StartExposure %4.2f - Should never get here",duration);
1265  return false;
1266 }
1267 
1268 bool INDI::CCD::StartGuideExposure(float duration)
1269 {
1270  DEBUGF(INDI::Logger::DBG_WARNING, "INDI::CCD::StartGuide Exposure %4.2f - Should never get here",duration);
1271  return false;
1272 }
1273 
1275 {
1276  DEBUG(INDI::Logger::DBG_WARNING, "INDI::CCD::AbortExposure - Should never get here");
1277  return false;
1278 }
1279 
1281 {
1282  DEBUG(INDI::Logger::DBG_WARNING, "INDI::CCD::AbortGuideExposure - Should never get here");
1283  return false;
1284 }
1285 
1286 bool INDI::CCD::UpdateCCDFrame(int x, int y, int w, int h)
1287 {
1288  // Just set value, unless HW layer overrides this and performs its own processing
1289  PrimaryCCD.setFrame(x, y, w, h);
1290  return true;
1291 }
1292 
1293 bool INDI::CCD::UpdateGuiderFrame(int x, int y, int w, int h)
1294 {
1295  GuideCCD.setFrame(x,y, w,h);
1296  return true;
1297 }
1298 
1299 bool INDI::CCD::UpdateCCDBin(int hor, int ver)
1300 {
1301  // Just set value, unless HW layer overrides this and performs its own processing
1302  PrimaryCCD.setBin(hor,ver);
1303  return true;
1304 }
1305 
1306 bool INDI::CCD::UpdateGuiderBin(int hor, int ver)
1307 {
1308  // Just set value, unless HW layer overrides this and performs its own processing
1309  GuideCCD.setBin(hor, ver);
1310  return true;
1311 }
1312 
1313 bool INDI::CCD::UpdateCCDFrameType(CCDChip::CCD_FRAME fType)
1314 {
1315  INDI_UNUSED(fType);
1316  // Child classes can override this
1317  return true;
1318 }
1319 
1320 bool INDI::CCD::UpdateGuiderFrameType(CCDChip::CCD_FRAME fType)
1321 {
1322  INDI_UNUSED(fType);
1323  // Child classes can override this
1324  return true;
1325 }
1326 
1327 void INDI::CCD::addFITSKeywords(fitsfile *fptr, CCDChip *targetChip)
1328 {
1329  int status=0;
1330  char frame_s[32];
1331  char dev_name[32];
1332  char exp_start[32];
1333  double min_val, max_val;
1334  double exposureDuration;
1335  double pixSize1,pixSize2;
1336  unsigned int xbin, ybin;
1337 
1338  setlocale(LC_NUMERIC,"C");
1339 
1340  if (targetChip->getNAxis() == 2)
1341  getMinMax(&min_val, &max_val, targetChip);
1342 
1343  xbin = targetChip->getBinX();
1344  ybin = targetChip->getBinY();
1345 
1346  char myDevice[MAXINDIDEVICE];
1347  strncpy(myDevice, getDeviceName(), MAXINDIDEVICE);
1348  fits_update_key_s(fptr, TSTRING, "INSTRUME", myDevice, "CCD Name" , &status);
1349 
1350  switch (targetChip->getFrameType())
1351  {
1352  case CCDChip::LIGHT_FRAME:
1353  strcpy(frame_s, "Light");
1354  break;
1355  case CCDChip::BIAS_FRAME:
1356  strcpy(frame_s, "Bias");
1357  break;
1358  case CCDChip::FLAT_FRAME:
1359  strcpy(frame_s, "Flat Field");
1360  break;
1361  case CCDChip::DARK_FRAME:
1362  strcpy(frame_s, "Dark");
1363  break;
1364  }
1365 
1366  exposureDuration = targetChip->getExposureDuration();
1367 
1368  pixSize1 = targetChip->getPixelSizeX();
1369  pixSize2 = targetChip->getPixelSizeY();
1370 
1371  strncpy(dev_name, getDeviceName(), 32);
1372  strncpy(exp_start, targetChip->getExposureStartTime(), 32);
1373 
1374  fits_update_key_s(fptr, TDOUBLE, "EXPTIME", &(exposureDuration), "Total Exposure Time (s)", &status);
1375 
1376  if(targetChip->getFrameType() == CCDChip::DARK_FRAME)
1377  fits_update_key_s(fptr, TDOUBLE, "DARKTIME", &(exposureDuration), "Total Exposure Time (s)", &status);
1378 
1379  if (capability.hasCooler)
1380  fits_update_key_s(fptr, TDOUBLE, "CCD-TEMP" , &(TemperatureN[0].value), "CCD Temperature (Celcius)", &status);
1381 
1382  fits_update_key_s(fptr, TDOUBLE, "PIXSIZE1", &(pixSize1), "Pixel Size 1 (microns)", &status);
1383  fits_update_key_s(fptr, TDOUBLE, "PIXSIZE2", &(pixSize2), "Pixel Size 2 (microns)", &status);
1384  fits_update_key_s(fptr, TUINT, "XBINNING", &(xbin) , "Binning factor in width", &status);
1385  fits_update_key_s(fptr, TUINT, "YBINNING", &(ybin), "Binning factor in height", &status);
1386  fits_update_key_s(fptr, TSTRING, "FRAME", frame_s, "Frame Type", &status);
1387  if (CurrentFilterSlot != -1 && CurrentFilterSlot <= FilterNames.size())
1388  {
1389  char filter[32];
1390  strncpy(filter, FilterNames.at(CurrentFilterSlot-1).c_str(), 32);
1391  fits_update_key_s(fptr, TSTRING, "FILTER", filter, "Filter", &status);
1392  }
1393 
1394  if (targetChip->getNAxis() == 2)
1395  {
1396  fits_update_key_s(fptr, TDOUBLE, "DATAMIN", &min_val, "Minimum value", &status);
1397  fits_update_key_s(fptr, TDOUBLE, "DATAMAX", &max_val, "Maximum value", &status);
1398  }
1399 
1400  if (capability.hasBayer && targetChip->getNAxis() == 2)
1401  {
1402  unsigned int bayer_offset_x = atoi(BayerT[0].text);
1403  unsigned int bayer_offset_y = atoi(BayerT[1].text);
1404 
1405  fits_update_key_s(fptr, TUINT, "XBAYROFF", &bayer_offset_x, "X offset of Bayer array", &status);
1406  fits_update_key_s(fptr, TUINT, "YBAYROFF", &bayer_offset_y, "Y offset of Bayer array", &status);
1407  fits_update_key_s(fptr, TSTRING, "BAYERPAT", BayerT[2].text, "Bayer color pattern", &status);
1408  }
1409 
1410  if (targetChip->getFrameType() == CCDChip::LIGHT_FRAME && RA != -1000 && Dec != -1000)
1411  {
1412  ln_equ_posn epochPos, J2000Pos;
1413  epochPos.ra = RA*15.0;
1414  epochPos.dec = Dec;
1415 
1416  // Convert from JNow to J2000
1417  //TODO use exp_start instead of julian from system
1418  ln_get_equ_prec2(&epochPos, ln_get_julian_from_sys(), JD2000, &J2000Pos);
1419 
1420  double raJ2000 = J2000Pos.ra/15.0;
1421  double decJ2000 = J2000Pos.dec;
1422 
1423  fits_update_key_s(fptr, TDOUBLE, "OBJCTRA", &raJ2000, "Object RA", &status);
1424  fits_update_key_s(fptr, TDOUBLE, "OBJCTDEC", &decJ2000, "Object DEC", &status);
1425 
1426  int epoch = 2000;
1427 
1428  fits_update_key_s(fptr, TINT, "EPOCH", &epoch, "Epoch", &status);
1429  fits_update_key_s(fptr, TINT, "EQUINOX", &epoch, "Equinox", &status);
1430 
1431 
1432  // Add WCS Info
1433  if (WorldCoordS[0].s == ISS_ON && ValidCCDRotation && FocalLength != -1)
1434  {
1435  raJ2000 *= 15;
1436  fits_update_key_s(fptr, TDOUBLE, "CRVAL1", &raJ2000, "CRVAL1", &status);
1437  fits_update_key_s(fptr, TDOUBLE, "CRVAL2", &decJ2000, "CRVAL1", &status);
1438 
1439  char radecsys[8] = "FK5";
1440  char ctype1[16] = "RA---TAN";
1441  char ctype2[16] = "DEC--TAN";
1442 
1443  fits_update_key_s(fptr, TSTRING, "RADECSYS", radecsys, "RADECSYS", &status);
1444  fits_update_key_s(fptr, TSTRING, "CTYPE1", ctype1, "CTYPE1", &status);
1445  fits_update_key_s(fptr, TSTRING, "CTYPE2", ctype2, "CTYPE2", &status);
1446 
1447  double crpix1 = targetChip->getSubW()/targetChip->getBinX()/2.0;
1448  double crpix2 = targetChip->getSubH()/targetChip->getBinY()/2.0;
1449 
1450  fits_update_key_s(fptr, TDOUBLE, "CRPIX1", &crpix1, "CRPIX1", &status);
1451  fits_update_key_s(fptr, TDOUBLE, "CRPIX2", &crpix2, "CRPIX2", &status);
1452 
1453  double secpix1 = pixSize1 / FocalLength * 206.3 * targetChip->getBinX();
1454  double secpix2 = pixSize2 / FocalLength * 206.3 * targetChip->getBinY();
1455 
1456  //double secpix1 = pixSize1 / FocalLength * 206.3;
1457  //double secpix2 = pixSize2 / FocalLength * 206.3;
1458 
1459  fits_update_key_s(fptr, TDOUBLE, "SECPIX1", &secpix1, "SECPIX1", &status);
1460  fits_update_key_s(fptr, TDOUBLE, "SECPIX2", &secpix2, "SECPIX2", &status);
1461 
1462  double degpix1 = secpix1 / 3600.0;
1463  double degpix2 = secpix2 / 3600.0;
1464 
1465  fits_update_key_s(fptr, TDOUBLE, "CDELT1", &degpix1, "CDELT1", &status);
1466  fits_update_key_s(fptr, TDOUBLE, "CDELT2", &degpix2, "CDELT2", &status);
1467 
1468  // Rotation is CW, we need to convert it to CCW per CROTA1 definition
1469  double rotation = 360 - CCDRotationN[0].value;
1470  if (rotation > 360)
1471  rotation -= 360;
1472 
1473  fits_update_key_s(fptr, TDOUBLE, "CROTA1", &rotation, "CROTA1", &status);
1474  fits_update_key_s(fptr, TDOUBLE, "CROTA2", &rotation, "CROTA2", &status);
1475 
1476  /*double cd[4];
1477  cd[0] = degpix1;
1478  cd[1] = 0;
1479  cd[2] = 0;
1480  cd[3] = degpix2;
1481 
1482  fits_update_key_s(fptr, TDOUBLE, "CD1_1", &cd[0], "CD1_1", &status);
1483  fits_update_key_s(fptr, TDOUBLE, "CD1_2", &cd[1], "CD1_2", &status);
1484  fits_update_key_s(fptr, TDOUBLE, "CD2_1", &cd[2], "CD2_1", &status);
1485  fits_update_key_s(fptr, TDOUBLE, "CD2_2", &cd[3], "CD2_2", &status);*/
1486 
1487  }
1488 
1489  }
1490 
1491  fits_update_key_s(fptr, TSTRING, "DATE-OBS", exp_start, "UTC start date of observation", &status);
1492  fits_write_comment(fptr, "Generated by INDI", &status);
1493 
1494  setlocale(LC_NUMERIC,"");
1495 
1496 }
1497 
1498 void INDI::CCD::fits_update_key_s(fitsfile* fptr, int type, std::string name, void* p, std::string explanation, int* status)
1499 {
1500  // this function is for removing warnings about deprecated string conversion to char* (from arg 5)
1501  fits_update_key(fptr,type,name.c_str(),p, const_cast<char*>(explanation.c_str()), status);
1502 }
1503 
1505 {
1506  bool sendImage = (UploadS[0].s == ISS_ON || UploadS[2].s == ISS_ON);
1507  bool saveImage = (UploadS[1].s == ISS_ON || UploadS[2].s == ISS_ON);
1508  bool showMarker = false;
1509  bool autoLoop = false;
1510  bool sendData = false;
1511 
1512  if (RapidGuideEnabled && targetChip == &PrimaryCCD)
1513  {
1514  autoLoop = AutoLoop;
1515  sendImage = SendImage;
1516  showMarker = ShowMarker;
1517  sendData = true;
1518  saveImage = false;
1519  }
1520 
1521  if (GuiderRapidGuideEnabled && targetChip == &GuideCCD)
1522  {
1523  autoLoop = GuiderAutoLoop;
1524  sendImage = GuiderSendImage;
1525  showMarker = GuiderShowMarker;
1526  sendData = true;
1527  saveImage = false;
1528  }
1529 
1530  if (sendData)
1531  {
1532  static double P0 = 0.906, P1 = 0.584, P2 = 0.365, P3 = 0.117, P4 = 0.049, P5 = -0.05, P6 = -0.064, P7 = -0.074, P8 = -0.094;
1533  targetChip->RapidGuideDataNP.s=IPS_BUSY;
1534  int width = targetChip->getSubW() / targetChip->getBinX();
1535  int height = targetChip->getSubH() / targetChip->getBinY();
1536  unsigned short *src = (unsigned short *) targetChip->getFrameBuffer();
1537  int i0, i1, i2, i3, i4, i5, i6, i7, i8;
1538  int ix = 0, iy = 0;
1539  int xM4;
1540  unsigned short *p;
1541  double average, fit, bestFit = 0;
1542  int minx = 4;
1543  int maxx = width -4;
1544  int miny = 4;
1545  int maxy = height -4;
1546  if (targetChip->lastRapidX > 0 && targetChip->lastRapidY > 0) {
1547  minx = std::max(targetChip->lastRapidX - 20, 4);
1548  maxx = std::min(targetChip->lastRapidX + 20, width - 4);
1549  miny = std::max(targetChip->lastRapidY - 20, 4);
1550  maxy = std::min(targetChip->lastRapidY + 20, height -4);
1551  }
1552  for (int x = minx; x < maxx; x++)
1553  for (int y = miny; y < maxy; y++)
1554  {
1555  i0 = i1 = i2 = i3 = i4 = i5 = i6 = i7 = i8 = 0;
1556  xM4 = x - 4;
1557  p = src + (y - 4) * width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++;
1558  p = src + (y - 3) * width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i7 += *p++; i6 += *p++; i7 += *p++; i8 += *p++; i8 += *p++; i8 += *p++;
1559  p = src + (y - 2) * width + xM4; i8 += *p++; i8 += *p++; i5 += *p++; i4 += *p++; i3 += *p++; i4 += *p++; i5 += *p++; i8 += *p++; i8 += *p++;
1560  p = src + (y - 1) * width + xM4; i8 += *p++; i7 += *p++; i4 += *p++; i2 += *p++; i1 += *p++; i2 += *p++; i4 += *p++; i8 += *p++; i8 += *p++;
1561  p = src + (y + 0) * width + xM4; i8 += *p++; i6 += *p++; i3 += *p++; i1 += *p++; i0 += *p++; i1 += *p++; i3 += *p++; i6 += *p++; i8 += *p++;
1562  p = src + (y + 1) * width + xM4; i8 += *p++; i7 += *p++; i4 += *p++; i2 += *p++; i1 += *p++; i2 += *p++; i4 += *p++; i8 += *p++; i8 += *p++;
1563  p = src + (y + 2) * width + xM4; i8 += *p++; i8 += *p++; i5 += *p++; i4 += *p++; i3 += *p++; i4 += *p++; i5 += *p++; i8 += *p++; i8 += *p++;
1564  p = src + (y + 3) * width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i7 += *p++; i6 += *p++; i7 += *p++; i8 += *p++; i8 += *p++; i8 += *p++;
1565  p = src + (y + 4) * width + xM4; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++; i8 += *p++;
1566  average = (i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8) / 85.0;
1567  fit = P0 * (i0 - average) + P1 * (i1 - 4 * average) + P2 * (i2 - 4 * average) + P3 * (i3 - 4 * average) + P4 * (i4 - 8 * average) + P5 * (i5 - 4 * average) + P6 * (i6 - 4 * average) + P7 * (i7 - 8 * average) + P8 * (i8 - 48 * average);
1568  if (bestFit < fit)
1569  {
1570  bestFit = fit;
1571  ix = x;
1572  iy = y;
1573  }
1574  }
1575 
1576  targetChip->RapidGuideDataN[0].value = ix;
1577  targetChip->RapidGuideDataN[1].value = iy;
1578  targetChip->RapidGuideDataN[2].value = bestFit;
1579  targetChip->lastRapidX = ix;
1580  targetChip->lastRapidY = iy;
1581  if (bestFit > 50)
1582  {
1583  int sumX = 0;
1584  int sumY = 0;
1585  int total = 0;
1586  int max = 0;
1587  int noiseThreshold = 0;
1588  for (int y = iy - 4; y <= iy + 4; y++) {
1589  p = src + y * width + ix - 4;
1590  for (int x = ix - 4; x <= ix + 4; x++) {
1591  int w = *p++;
1592  noiseThreshold += w;
1593  if (w > max)
1594  max = w;
1595  }
1596  }
1597  noiseThreshold = (noiseThreshold/81+max)/2; // set threshold between peak and average
1598  for (int y = iy - 4; y <= iy + 4; y++) {
1599  p = src + y * width + ix - 4;
1600  for (int x = ix - 4; x <= ix + 4; x++) {
1601  int w = *p++;
1602  if (w < noiseThreshold)
1603  w = 0;
1604  sumX += x * w;
1605  sumY += y * w;
1606  total += w;
1607  }
1608  }
1609  if (total > 0)
1610  {
1611  targetChip->RapidGuideDataN[0].value = ((double)sumX)/total;
1612  targetChip->RapidGuideDataN[1].value = ((double)sumY)/total;
1613  targetChip->RapidGuideDataNP.s=IPS_OK;
1614 
1615  DEBUGF(INDI::Logger::DBG_DEBUG, "Guide Star X: %g Y: %g FIT: %g", targetChip->RapidGuideDataN[0].value, targetChip->RapidGuideDataN[1].value,
1616  targetChip->RapidGuideDataN[2].value);
1617  }
1618  else
1619  {
1620  targetChip->RapidGuideDataNP.s=IPS_ALERT;
1621  targetChip->lastRapidX = targetChip->lastRapidY = -1;
1622  }
1623  }
1624  else
1625  {
1626  targetChip->RapidGuideDataNP.s=IPS_ALERT;
1627  targetChip->lastRapidX = targetChip->lastRapidY = -1;
1628  }
1629  IDSetNumber(&targetChip->RapidGuideDataNP,NULL);
1630 
1631  if (showMarker)
1632  {
1633  int xmin = std::max(ix - 10, 0);
1634  int xmax = std::min(ix + 10, width - 1);
1635  int ymin = std::max(iy - 10, 0);
1636  int ymax = std::min(iy + 10, height - 1);
1637 
1638  //fprintf(stderr, "%d %d %d %d\n", xmin, xmax, ymin, ymax);
1639 
1640  if (ymin > 0)
1641  {
1642  p = src + ymin * width + xmin;
1643  for (int x = xmin; x <= xmax; x++)
1644  *p++ = 50000;
1645  }
1646 
1647  if (xmin > 0)
1648  {
1649  for (int y = ymin; y<= ymax; y++)
1650  {
1651  *(src + y * width + xmin) = 50000;
1652  }
1653  }
1654 
1655  if (xmax < width - 1)
1656  {
1657  for (int y = ymin; y<= ymax; y++)
1658  {
1659  *(src + y * width + xmax) = 50000;
1660  }
1661  }
1662 
1663  if (ymax < height -1)
1664  {
1665  p = src + ymax * width + xmin;
1666  for (int x = xmin; x <= xmax; x++)
1667  *p++ = 50000;
1668  }
1669  }
1670  }
1671 
1672  if (sendImage || saveImage)
1673  {
1674  if (!strcmp(targetChip->getImageExtension(), "fits"))
1675  {
1676  void *memptr;
1677  size_t memsize;
1678  int img_type=0;
1679  int byte_type=0;
1680  int status=0;
1681  long naxis=targetChip->getNAxis();
1682  long naxes[naxis];
1683  int nelements=0;
1684  std::string bit_depth;
1685 
1686  fitsfile *fptr=NULL;
1687 
1688  naxes[0]=targetChip->getSubW()/targetChip->getBinX();
1689  naxes[1]=targetChip->getSubH()/targetChip->getBinY();
1690 
1691  switch (targetChip->getBPP())
1692  {
1693  case 8:
1694  byte_type = TBYTE;
1695  img_type = BYTE_IMG;
1696  bit_depth = "8 bits per pixel";
1697  break;
1698 
1699  case 16:
1700  byte_type = TUSHORT;
1701  img_type = USHORT_IMG;
1702  bit_depth = "16 bits per pixel";
1703  break;
1704 
1705  case 32:
1706  byte_type = TULONG;
1707  img_type = ULONG_IMG;
1708  bit_depth = "32 bits per pixel";
1709  break;
1710 
1711  default:
1712  DEBUGF(Logger::DBG_WARNING, "Unsupported bits per pixel value %d\n", targetChip->getBPP() );
1713  return false;
1714  break;
1715  }
1716 
1717  nelements = naxes[0] * naxes[1];
1718  if (naxis== 3)
1719  {
1720  nelements *= 3;
1721  naxes[2] = 3;
1722  }
1723 
1724  /*DEBUGF(Logger::DBG_DEBUG, "Exposure complete. Image Depth: %s. Width: %d Height: %d nelements: %d", bit_depth.c_str(), naxes[0],
1725  naxes[1], nelements);*/
1726 
1727  // Now we have to send fits format data to the client
1728  memsize=5760;
1729  memptr=malloc(memsize);
1730  if(!memptr)
1731  {
1732  IDLog("Error: failed to allocate memory: %lu\n",(unsigned long)memsize);
1733  }
1734 
1735  fits_create_memfile(&fptr,&memptr,&memsize,2880,realloc,&status);
1736 
1737  if(status)
1738  {
1739  IDLog("Error: Failed to create FITS image\n");
1740  fits_report_error(stderr, status); /* print out any error messages */
1741  return false;
1742  }
1743 
1744  fits_create_img(fptr, img_type , naxis, naxes, &status);
1745 
1746  if (status)
1747  {
1748  IDLog("Error: Failed to create FITS image\n");
1749  fits_report_error(stderr, status); /* print out any error messages */
1750  return false;
1751  }
1752 
1753  addFITSKeywords(fptr, targetChip);
1754 
1755  fits_write_img(fptr,byte_type,1,nelements,targetChip->getFrameBuffer(),&status);
1756 
1757  if (status)
1758  {
1759  IDLog("Error: Failed to write FITS image\n");
1760  fits_report_error(stderr, status); /* print out any error messages */
1761  return false;
1762  }
1763 
1764  fits_close_file(fptr,&status);
1765 
1766  uploadFile(targetChip, memptr, memsize, sendImage, saveImage);
1767 
1768  free(memptr);
1769  }
1770  else
1771  {
1772  uploadFile(targetChip, targetChip->getFrameBuffer(), targetChip->getFrameBufferSize(), sendImage, saveImage);
1773  }
1774 
1775 
1776  }
1777 
1778  targetChip->ImageExposureNP.s=IPS_OK;
1779  IDSetNumber(&targetChip->ImageExposureNP,NULL);
1780 
1781  if (autoLoop)
1782  {
1783  if (targetChip == &PrimaryCCD)
1784  {
1785  PrimaryCCD.ImageExposureN[0].value = ExposureTime;
1786  PrimaryCCD.ImageExposureNP.s=IPS_BUSY;
1787  if (StartExposure(ExposureTime))
1788  PrimaryCCD.ImageExposureNP.s=IPS_BUSY;
1789  else
1790  {
1791  DEBUG(INDI::Logger::DBG_DEBUG, "Autoloop: Primary CCD Exposure Error!");
1792  PrimaryCCD.ImageExposureNP.s=IPS_ALERT;
1793  }
1794 
1795  IDSetNumber(&PrimaryCCD.ImageExposureNP,NULL);
1796  }
1797  else
1798  {
1799  GuideCCD.ImageExposureN[0].value = GuiderExposureTime;
1800  GuideCCD.ImageExposureNP.s=IPS_BUSY;
1801  if (StartGuideExposure(GuiderExposureTime))
1802  GuideCCD.ImageExposureNP.s=IPS_BUSY;
1803  else
1804  {
1805  DEBUG(INDI::Logger::DBG_DEBUG, "Autoloop: Guide CCD Exposure Error!");
1806  GuideCCD.ImageExposureNP.s=IPS_ALERT;
1807  }
1808 
1809  IDSetNumber(&GuideCCD.ImageExposureNP,NULL);
1810  }
1811  }
1812 
1813  return true;
1814 }
1815 
1816 bool INDI::CCD::uploadFile(CCDChip * targetChip, const void *fitsData, size_t totalBytes, bool sendImage, bool saveImage)
1817 {
1818  unsigned char *compressedData = NULL;
1819  uLongf compressedBytes=0;
1820 
1821  if (saveImage)
1822  {
1823  targetChip->FitsB.blob=(unsigned char *)fitsData;
1824  targetChip->FitsB.bloblen=totalBytes;
1825  snprintf(targetChip->FitsB.format, MAXINDIBLOBFMT, ".%s", targetChip->getImageExtension());
1826 
1827  FILE *fp = NULL;
1828  char imageFileName[MAXRBUF];
1829  std::string prefix = UploadSettingsT[1].text;
1830  int maxIndex = getFileIndex(UploadSettingsT[0].text, UploadSettingsT[1].text, targetChip->FitsB.format);
1831 
1832  if (maxIndex < 0)
1833  {
1834  DEBUGF(INDI::Logger::DBG_ERROR, "Error iterating directory %s. %s", UploadSettingsT[0].text, strerror(errno));
1835  return false;
1836  }
1837 
1838  if (maxIndex > 0)
1839  {
1840  char indexString[4];
1841  snprintf(indexString, 4, "%03d", maxIndex);
1842  std::string prefixIndex = indexString;
1843  prefix.replace(prefix.find("XXX"), 3, prefixIndex);
1844  }
1845 
1846  snprintf(imageFileName, MAXRBUF, "%s/%s%s", UploadSettingsT[0].text, prefix.c_str(), targetChip->FitsB.format);
1847  fp = fopen(imageFileName, "w");
1848  if (fp == NULL)
1849  {
1850  DEBUGF(INDI::Logger::DBG_ERROR, "Unable to save image file (%s). %s", imageFileName, strerror(errno));
1851  return false;
1852  }
1853 
1854  int n=0;
1855  for (int nr=0; nr < (int) targetChip->FitsB.bloblen; nr += n)
1856  n = fwrite( (static_cast<char *>(targetChip->FitsB.blob) + nr), 1, targetChip->FitsB.bloblen - nr, fp);
1857 
1858  DEBUGF(INDI::Logger::DBG_SESSION, "Image saved to %s", imageFileName);
1859  fclose(fp);
1860  }
1861 
1862  if (targetChip->SendCompressed)
1863  {
1864  compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
1865  compressedData = (unsigned char *) malloc (compressedBytes);
1866 
1867  if (fitsData == NULL || compressedData == NULL)
1868  {
1869  if (compressedData)
1870  free(compressedData);
1871  DEBUG(INDI::Logger::DBG_ERROR, "Error: Ran out of memory compressing image");
1872  return false;
1873  }
1874 
1875  int r = compress2(compressedData, &compressedBytes, (const Bytef*)fitsData, totalBytes, 9);
1876  if (r != Z_OK)
1877  {
1878  /* this should NEVER happen */
1879  DEBUG(INDI::Logger::DBG_ERROR, "Error: Failed to compress image");
1880  return false;
1881  }
1882 
1883  targetChip->FitsB.blob=compressedData;
1884  targetChip->FitsB.bloblen=compressedBytes;
1885  snprintf(targetChip->FitsB.format, MAXINDIBLOBFMT, ".%s.z", targetChip->getImageExtension());
1886  } else
1887  {
1888  targetChip->FitsB.blob=(unsigned char *)fitsData;
1889  targetChip->FitsB.bloblen=totalBytes;
1890  snprintf(targetChip->FitsB.format, MAXINDIBLOBFMT, ".%s", targetChip->getImageExtension());
1891  }
1892 
1893  targetChip->FitsB.size = totalBytes;
1894  targetChip->FitsBP.s=IPS_OK;
1895 
1896  if (sendImage)
1897  IDSetBLOB(&targetChip->FitsBP,NULL);
1898 
1899  if (compressedData)
1900  free (compressedData);
1901 
1902  return true;
1903 }
1904 
1905 void INDI::CCD::SetCCDParams(int x,int y,int bpp,float xf,float yf)
1906 {
1907  PrimaryCCD.setResolution(x, y);
1908  PrimaryCCD.setFrame(0, 0, x, y);
1909  if (capability.canBin)
1910  PrimaryCCD.setBin(1,1);
1911  PrimaryCCD.setPixelSize(xf, yf);
1912  PrimaryCCD.setBPP(bpp);
1913 
1914 }
1915 
1916 void INDI::CCD::SetGuiderParams(int x,int y,int bpp,float xf,float yf)
1917 {
1918  capability.hasGuideHead=true;
1919 
1920  GuideCCD.setResolution(x, y);
1921  GuideCCD.setFrame(0, 0, x, y);
1922  GuideCCD.setPixelSize(xf, yf);
1923  GuideCCD.setBPP(bpp);
1924 
1925 }
1926 
1927 bool INDI::CCD::saveConfigItems(FILE *fp)
1928 {
1929  IUSaveConfigText(fp, &ActiveDeviceTP);
1930  IUSaveConfigSwitch(fp, &UploadSP);
1931  IUSaveConfigText(fp, &UploadSettingsTP);
1932  //IUSaveConfigSwitch(fp, &WorldCoordSP);
1933  IUSaveConfigSwitch(fp, &TelescopeTypeSP);
1934 
1935  //if (ValidCCDRotation)
1936  // IUSaveConfigNumber(fp, &CCDRotationNP);
1937 
1938  IUSaveConfigSwitch(fp, &PrimaryCCD.CompressSP);
1939 
1940  if (capability.hasGuideHead)
1941  IUSaveConfigSwitch(fp, &GuideCCD.CompressSP);
1942 
1943  if (capability.canSubFrame)
1944  IUSaveConfigNumber(fp, &PrimaryCCD.ImageFrameNP);
1945 
1946  if (capability.canBin)
1947  IUSaveConfigNumber(fp, &PrimaryCCD.ImageBinNP);
1948 
1949  if (capability.hasBayer)
1950  IUSaveConfigText(fp, &BayerTP);
1951 
1952  return true;
1953 }
1954 
1956 {
1957  INDI_UNUSED(ms);
1958  DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding.");
1959  return IPS_ALERT;
1960 }
1961 
1963 {
1964  INDI_UNUSED(ms);
1965  DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding.");
1966  return IPS_ALERT;
1967 }
1968 
1970 {
1971  INDI_UNUSED(ms);
1972  DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding.");
1973  return IPS_ALERT;
1974 }
1975 
1977 {
1978  INDI_UNUSED(ms);
1979  DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding.");
1980  return IPS_ALERT;
1981 }
1982 
1983 void INDI::CCD::getMinMax(double *min, double *max, CCDChip *targetChip)
1984 {
1985  int ind=0, i, j;
1986  int imageHeight = targetChip->getSubH() / targetChip->getBinY();
1987  int imageWidth = targetChip->getSubW() / targetChip->getBinX();
1988  double lmin, lmax;
1989 
1990  switch (targetChip->getBPP())
1991  {
1992  case 8:
1993  {
1994  unsigned char *imageBuffer = (unsigned char *) targetChip->getFrameBuffer();
1995  lmin = lmax = imageBuffer[0];
1996 
1997 
1998  for (i= 0; i < imageHeight ; i++)
1999  for (j= 0; j < imageWidth; j++)
2000  {
2001  ind = (i * imageWidth) + j;
2002  if (imageBuffer[ind] < lmin) lmin = imageBuffer[ind];
2003  else if (imageBuffer[ind] > lmax) lmax = imageBuffer[ind];
2004  }
2005 
2006  }
2007  break;
2008 
2009  case 16:
2010  {
2011  unsigned short *imageBuffer = (unsigned short* ) targetChip->getFrameBuffer();
2012  lmin = lmax = imageBuffer[0];
2013 
2014  for (i= 0; i < imageHeight ; i++)
2015  for (j= 0; j < imageWidth; j++)
2016  {
2017  ind = (i * imageWidth) + j;
2018  if (imageBuffer[ind] < lmin) lmin = imageBuffer[ind];
2019  else if (imageBuffer[ind] > lmax) lmax = imageBuffer[ind];
2020  }
2021 
2022  }
2023  break;
2024 
2025  case 32:
2026  {
2027  unsigned int *imageBuffer = (unsigned int* ) targetChip->getFrameBuffer();
2028  lmin = lmax = imageBuffer[0];
2029 
2030  for (i= 0; i < imageHeight ; i++)
2031  for (j= 0; j < imageWidth; j++)
2032  {
2033  ind = (i * imageWidth) + j;
2034  if (imageBuffer[ind] < lmin) lmin = imageBuffer[ind];
2035  else if (imageBuffer[ind] > lmax) lmax = imageBuffer[ind];
2036 
2037  }
2038 
2039  }
2040  break;
2041 
2042  }
2043  *min = lmin;
2044  *max = lmax;
2045 }
2046 
2047 int INDI::CCD::getFileIndex(const char *dir, const char *prefix, const char *ext)
2048 {
2049  DIR *dpdf;
2050  struct dirent *epdf;
2051  std::vector<std::string> files = std::vector<std::string>();
2052 
2053  std::string prefixIndex = prefix;
2054  if (prefixIndex.find("XXX") == std::string::npos)
2055  return 0;
2056 
2057  std::string prefixSearch = prefix;
2058  prefixSearch.replace(prefixSearch.find("XXX"), 3, "");
2059 
2060  dpdf = opendir(dir);
2061  if (dpdf != NULL)
2062  {
2063  while (epdf = readdir(dpdf))
2064  {
2065  if (strstr(epdf->d_name, prefixSearch.c_str()))
2066  files.push_back(epdf->d_name);
2067  }
2068  }
2069  else
2070  return -1;
2071 
2072  int maxIndex=0;
2073 
2074  std::string filterIndex = "%d";
2075  prefixIndex.replace(prefixIndex.find("XXX"), 3, filterIndex);
2076  char filter[MAXRBUF];
2077  snprintf(filter, MAXRBUF, "%s%s", prefixIndex.c_str(), ext);
2078  for (int i=0; i < files.size(); i++)
2079  {
2080  int index=-1;
2081  sscanf(files.at(i).c_str(), filter, &index);
2082  if (index > maxIndex)
2083  maxIndex=index;
2084  }
2085 
2086  return (maxIndex+1);
2087 
2088 }
2089 
2090 void INDI::CCD::GuideComplete(INDI_EQ_AXIS axis)
2091 {
2093 }
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver...
Definition: indiccd.cpp:474
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indidriver.c:1347
void setPixelSize(float x, float y)
setPixelSize Set CCD Chip pixel size
Definition: indiccd.cpp:152
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1221
int getSubH()
getSubH Get the height of the frame
Definition: indiccd.h:90
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1211
void setFrameBufferSize(int nbuf, bool allocMem=true)
setFrameBufferSize Set desired frame buffer size. The function will allocate memory accordingly...
Definition: indiccd.cpp:174
void setBin(int hor, int ver)
setBin Set CCD Chip binnig
Definition: indiccd.cpp:112
void setFrameType(CCD_FRAME type)
setFrameType Set desired frame type for next exposure.
Definition: indiccd.cpp:70
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
virtual void addFITSKeywords(fitsfile *fptr, CCDChip *targetChip)
Add FITS keywords to a fits file.
Definition: indiccd.cpp:1327
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
Definition: indiccd.cpp:732
virtual bool UpdateCCDFrame(int x, int y, int w, int h)
INDI::CCD calls this function when CCD Frame dimension needs to be updated in the hardware...
Definition: indiccd.cpp:1286
virtual bool StartExposure(float duration)
Start exposing primary CCD chip.
Definition: indiccd.cpp:1262
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:503
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minumum set of properties are defined t...
void setExposureDuration(double duration)
setExposureDuration Set desired CCD frame exposure duration for next exposure. You must call this fun...
Definition: indiccd.cpp:194
void setExposureLeft(double duration)
setExposureLeft Update exposure time left. Inform the client of the new exposure time left value...
Definition: indiccd.cpp:187
char format[MAXINDIBLOBFMT]
Definition: indiapi.h:376
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.c:394
void IDSetText(const ITextVectorProperty *t, const char *msg,...)
Tell client to update an existing text vector property.
Definition: indidriver.c:1700
void SetCCDCapability(CCDCapability *cap)
SetCCDCapability Set the CCD capabilities. Al fields must be initilized.
Definition: indiccd.cpp:282
void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...)
Tell client to update an existing switch vector property.
Definition: indidriver.c:1780
double step
Definition: indiapi.h:243
IPState
Property state.
Definition: indiapi.h:129
void setImageExtension(const char *ext)
setImageExtension Set image exntension
Definition: indiccd.cpp:238
virtual IPState GuideEast(float ms)
Guide easward for ms milliseconds.
Definition: indiccd.cpp:1969
void setResolution(int x, int y)
setResolution set CCD Chip resolution
Definition: indiccd.cpp:75
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:209
const char * getFrameTypeName(CCD_FRAME fType)
getFrameTypeName returns CCD Frame type name
Definition: indiccd.cpp:200
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:300
One number descriptor.
Definition: indiapi.h:238
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:263
virtual bool StartGuideExposure(float duration)
Start exposing guide CCD chip.
Definition: indiccd.cpp:1268
Definition: indiapi.h:153
double getExposureDuration()
getExposureDuration Get requested exposure duration for the CCD chip in seconds.
Definition: indiccd.h:138
Definition: indiapi.h:152
int getNAxis() const
Definition: indiccd.cpp:228
int size
Definition: indiapi.h:382
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1908
Definition: indiapi.h:154
virtual int SetTemperature(double temperature)
Set CCD temperature.
Definition: indiccd.cpp:1255
int getFrameBufferSize()
getFrameBufferSize Get allocated frame buffer size to hold the CCD image frame.
Definition: indiccd.h:126
float getPixelSizeY()
getPixelSizeY Get vertical pixel size in microns.
Definition: indiccd.h:114
virtual bool UpdateGuiderFrameType(CCDChip::CCD_FRAME fType)
INDI::CCD calls this function when Guide frame type is updated by the client.
Definition: indiccd.cpp:1320
float getPixelSizeX()
getPixelSizeX Get horizontal pixel size in microns.
Definition: indiccd.h:108
void IDSetNumber(const INumberVectorProperty *n, const char *msg,...)
Tell client to update an existing number vector property.
Definition: indidriver.c:1740
void setExposureFailed()
setExposureFailed Alert the client that the exposure failed.
Definition: indiccd.cpp:222
virtual void SetCCDParams(int x, int y, int bpp, float xf, float yf)
Setup CCD paramters for primary CCD. Child classes call this function to update CCD paramaters...
Definition: indiccd.cpp:1905
char name[MAXINDINAME]
Definition: indiapi.h:270
int bloblen
Definition: indiapi.h:380
void setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient=true)
setMinMaxStep for a number property element
Definition: indiccd.cpp:124
int IUSnoopNumber(XMLEle *root, INumberVectorProperty *nvp)
Update a snooped number vector property from the given XML root element.
Definition: indidriver.c:579
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL...
Definition: indidriver.c:419
void IUFillBLOB(IBLOB *bp, const char *name, const char *label, const char *format)
Assign attributes for a BLOB property. The BLOB's data and auxiliary elements will be set to NULL...
Definition: indidriver.c:439
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function...
Definition: indiccd.cpp:294
void setNAxis(int value)
setNAxis Set FITS number of axis
Definition: indiccd.cpp:233
The CCDChip class provides functionality of a CCD Chip within a CCD.
Definition: indiccd.h:44
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidriver.c:1328
virtual bool UpdateCCDFrameType(CCDChip::CCD_FRAME fType)
INDI::CCD calls this function when CCD frame type needs to be updated in the hardware.
Definition: indiccd.cpp:1313
char * getFrameBuffer()
getFrameBuffer Get raw frame buffer of the CCD chip.
Definition: indiccd.h:150
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL...
Definition: indidriver.c:367
void setFrame(int subx, int suby, int subw, int subh)
setFrame Set desired frame resolutoin for an exposure.
Definition: indiccd.cpp:97
void setInterlaced(bool intr)
setInterlaced Set whether the CCD chip is interlaced or not?
Definition: indiccd.cpp:217
void * blob
Definition: indiapi.h:378
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL...
Definition: indidriver.c:398
char * getImageExtension()
Definition: indiccd.h:302
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indidriver.c:1365
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1133
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
Definition: indidriver.c:120
Number vector property descriptor.
Definition: indiapi.h:266
void IDSetBLOB(const IBLOBVectorProperty *b, const char *msg,...)
Tell client to update an existing BLOB vector property.
Definition: indidriver.c:1857
int getBinX()
getBinX Get horizontal binning of the CCD chip.
Definition: indiccd.h:96
double min
Definition: indiapi.h:242
virtual void SetGuiderParams(int x, int y, int bpp, float xf, float yf)
Setup CCD paramters for guide head CCD. Child classes call this function to update CCD paramaters...
Definition: indiccd.cpp:1916
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
int getSubW()
getSubW Get the width of the frame
Definition: indiccd.h:84
virtual bool UpdateCCDBin(int hor, int ver)
INDI::CCD calls this function when CCD Binning needs to be updated in the hardware. Derived classes should implement this function.
Definition: indiccd.cpp:1299
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual IPState GuideWest(float ms)
Guide westward for ms milliseconds.
Definition: indiccd.cpp:1976
void IDLog(const char *msg,...)
Function Drivers call to log a message locally.
Definition: indicom.c:228
const char * getExposureStartTime()
getExposureStartTime
Definition: indiccd.cpp:205
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
void IUFillBLOBVector(IBLOBVectorProperty *bvp, IBLOB *bp, int nbp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a BLOB vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:547
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function...
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: indiccd.cpp:620
Holds the capabilities of the CCD. All fields must be initialized.
Definition: indiccd.h:391
CCD_FRAME getFrameType()
getFrameType
Definition: indiccd.h:176
ISState
Switch state.
Definition: indiapi.h:120
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:460
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.c:439
virtual bool AbortExposure()
Abort ongoing exposure.
Definition: indiccd.cpp:1274
void GuideComplete(INDI_EQ_AXIS axis)
Call GuideComplete once the guiding pulse is complete.
Definition: indiccd.cpp:2090
int getBinY()
getBinY Get vertical binning of the CCD chip.
Definition: indiccd.h:102
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:526
void setBPP(int bpp)
setBPP Set depth of CCD chip.
Definition: indiccd.cpp:165
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.c:338
void fits_update_key_s(fitsfile *fptr, int type, std::string name, void *p, std::string explanation, int *status)
Definition: indiccd.cpp:1498
virtual IPState GuideSouth(float ms)
Guide southward for ms milliseconds.
Definition: indiccd.cpp:1962
virtual IPState GuideNorth(float ms)
Guide northward for ms milliseconds.
Definition: indiccd.cpp:1955
virtual bool AbortGuideExposure()
Abort ongoing exposure.
Definition: indiccd.cpp:1280
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
Definition: indiccd.cpp:682
virtual void GuideComplete(INDI_EQ_AXIS axis)
Call GuideComplete once the guiding pulse is complete.
virtual bool UpdateGuiderBin(int hor, int ver)
INDI::CCD calls this function when Guide head binning is updated by the client. Derived classes shoul...
Definition: indiccd.cpp:1306
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minumum set of properties are defined t...
Definition: indiccd.cpp:463
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
Definition: indiccd.cpp:985
virtual bool UpdateGuiderFrame(int x, int y, int w, int h)
INDI::CCD calls this function when Guide head frame dimension is updated by the client. Derived classes should implement this function.
Definition: indiccd.cpp:1293
int getBPP()
getBPP Get CCD Chip depth (bits per pixel).
Definition: indiccd.h:120
virtual bool ExposureComplete(CCDChip *targetChip)
Uploads target Chip exposed buffer as FITS to the client. Dervied classes should class this functon w...
Definition: indiccd.cpp:1504
double value
Definition: indiapi.h:244