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