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