source: BAORadio/libindi/v1.0.1/drivers/ccd/fli_ccd.c@ 674

Last change on this file since 674 was 490, checked in by campagne, 15 years ago

import libindi (JEC)

File size: 37.3 KB
Line 
1#if 0
2 FLI CCD
3 INDI Interface for Finger Lakes Instruments CCDs
4 Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20#endif
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <stdarg.h>
26#include <math.h>
27#include <unistd.h>
28#include <time.h>
29#include <fcntl.h>
30#include <errno.h>
31#include <sys/stat.h>
32#include <sys/time.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
36#include <netdb.h>
37#include <zlib.h>
38
39#include <fitsio.h>
40
41#include <libfli.h>
42#include "indidevapi.h"
43#include "eventloop.h"
44#include "indicom.h"
45
46void ISInit(void);
47void getBasicData(void);
48void ISPoll(void *);
49void handleExposure(void *);
50void connectCCD(void);
51void getBasicData(void);
52void uploadFile(const char* filename);
53int writeFITS(const char* filename, char errmsg[]);
54int findcam(flidomain_t domain);
55int setImageArea(char errmsg[]);
56int manageDefaults(char errmsg[]);
57int grabImage(void);
58int checkPowerS(ISwitchVectorProperty *sp);
59int checkPowerN(INumberVectorProperty *np);
60int checkPowerT(ITextVectorProperty *tp);
61int getOnSwitch(ISwitchVectorProperty *sp);
62int isCCDConnected(void);
63void addFITSKeywords(fitsfile *fptr);
64
65double min(void);
66double max(void);
67
68extern char* me;
69extern int errno;
70
71#define mydev "FLI CCD"
72
73#define COMM_GROUP "Communication"
74#define EXPOSE_GROUP "Expose"
75#define IMAGE_GROUP "Image Settings"
76#define DATA_GROUP "Data Channel"
77
78#define MAX_CCD_TEMP 45 /* Max CCD temperature */
79#define MIN_CCD_TEMP -55 /* Min CCD temperature */
80#define MAX_X_BIN 16. /* Max Horizontal binning */
81#define MAX_Y_BIN 16. /* Max Vertical binning */
82#define MAX_PIXELS 4096 /* Max number of pixels in one dimension */
83#define POLLMS 1000 /* Polling time (ms) */
84#define TEMP_THRESHOLD .25 /* Differential temperature threshold (C)*/
85#define NFLUSHES 1 /* Number of times a CCD array is flushed before an exposure */
86
87#define FILENAMESIZ 2048
88#define LIBVERSIZ 1024
89#define PREFIXSIZ 64
90#define PIPEBUFSIZ 8192
91#define FRAME_ILEN 64
92#define TEMPFILE_LEN 16
93
94enum FLIFrames { LIGHT_FRAME = 0, BIAS_FRAME, DARK_FRAME, FLAT_FRAME };
95
96
97typedef struct {
98 flidomain_t domain;
99 char *dname;
100 char *name;
101 char *model;
102 long HWRevision;
103 long FWRevision;
104 double x_pixel_size;
105 double y_pixel_size;
106 long Array_Area[4];
107 long Visible_Area[4];
108 int width, height;
109 double temperature;
110} cam_t;
111
112typedef struct {
113int width;
114int height;
115int frameType;
116int expose;
117unsigned short *img;
118} img_t;
119
120/*static int streamTimerID; Stream ID */
121
122static flidev_t fli_dev;
123static cam_t *FLICam;
124static img_t *FLIImg;
125static int portSwitchIndex;
126
127long int Domains[] = { FLIDOMAIN_USB, FLIDOMAIN_SERIAL, FLIDOMAIN_PARALLEL_PORT, FLIDOMAIN_INET };
128
129/*INDI controls */
130
131/* Connect/Disconnect */
132static ISwitch ConnectS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
133static ISwitchVectorProperty ConnectSP = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0};
134
135/* Types of Ports */
136static ISwitch PortS[] = {{"USB", "", ISS_ON, 0, 0}, {"Serial", "", ISS_OFF, 0, 0}, {"Parallel", "", ISS_OFF, 0, 0}, {"INet", "", ISS_OFF, 0, 0}};
137static ISwitchVectorProperty PortSP = { mydev, "Port Type", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PortS, NARRAY(PortS), "", 0};
138
139/* Types of Frames */
140static ISwitch FrameTypeS[] = { {"FRAME_LIGHT", "Light", ISS_ON, 0, 0}, {"FRAME_BIAS", "Bias", ISS_OFF, 0, 0}, {"FRAME_DARK", "Dark", ISS_OFF, 0, 0}, {"FRAME_FLAT", "Flat Field", ISS_OFF, 0, 0}};
141static ISwitchVectorProperty FrameTypeSP = { mydev, "CCD_FRAME_TYPE", "Frame Type", EXPOSE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FrameTypeS, NARRAY(FrameTypeS), "", 0};
142
143/* Frame coordinates. Full frame is default */
144static INumber FrameN[] = {
145 { "X", "X", "%.0f", 0., MAX_PIXELS, 1., 0., 0, 0, 0},
146 { "Y", "Y", "%.0f", 0., MAX_PIXELS, 1., 0., 0, 0, 0},
147 { "WIDTH", "Width", "%.0f", 0., MAX_PIXELS, 1., 0., 0, 0, 0},
148 { "HEIGHT", "Height", "%.0f",0., MAX_PIXELS, 1., 0., 0, 0, 0}};
149 static INumberVectorProperty FrameNP = { mydev, "CCD_FRAME", "Frame", IMAGE_GROUP, IP_RW, 60, IPS_IDLE, FrameN, NARRAY(FrameN), "", 0};
150
151 /* Binning */
152 static INumber BinningN[] = {
153 { "HOR_BIN", "X", "%0.f", 1., MAX_X_BIN, 1., 1., 0, 0, 0},
154 { "VER_BIN", "Y", "%0.f", 1., MAX_Y_BIN, 1., 1., 0, 0, 0}};
155 static INumberVectorProperty BinningNP = { mydev, "CCD_BINNING", "Binning", IMAGE_GROUP, IP_RW, 60, IPS_IDLE, BinningN, NARRAY(BinningN), "", 0};
156
157 /* Exposure time */
158 static INumber ExposeTimeWN[] = {{ "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., .5, 1., 0, 0, 0}};
159 static INumberVectorProperty ExposeTimeWNP = { mydev, "CCD_EXPOSURE_REQUEST", "Expose", EXPOSE_GROUP, IP_WO, 36000, IPS_IDLE, ExposeTimeWN, NARRAY(ExposeTimeWN), "", 0};
160
161 static INumber ExposeTimeRN[] = {{ "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., .5, 1., 0, 0, 0}};
162 static INumberVectorProperty ExposeTimeRNP = { mydev, "CCD_EXPOSURE", "Expose", EXPOSE_GROUP, IP_RO, 36000, IPS_IDLE, ExposeTimeRN, NARRAY(ExposeTimeRN), "", 0};
163
164 /* Temperature control */
165 static INumber TemperatureN[] = { {"CCD_TEMPERATURE_VALUE", "Temperature", "%+06.2f", MIN_CCD_TEMP, MAX_CCD_TEMP, .2, 0., 0, 0, 0}};
166 static INumberVectorProperty TemperatureNP = { mydev, "CCD_TEMPERATURE", "Temperature (C)", EXPOSE_GROUP, IP_RW, 60, IPS_IDLE, TemperatureN, NARRAY(TemperatureN), "", 0};
167
168 /* Pixel size (µm) */
169static INumber PixelSizeN[] = {
170 { "Width", "", "%.0f", 0. , 0., 0., 0., 0, 0, 0},
171 { "Height", "", "%.0f", 0. , 0., 0., 0., 0, 0, 0}};
172static INumberVectorProperty PixelSizeNP = { mydev, "Pixel Size (µm)", "", DATA_GROUP, IP_RO, 0, IPS_IDLE, PixelSizeN, NARRAY(PixelSizeN), "", 0};
173
174/* BLOB for sending image */
175static IBLOB imageB = {"FITS_BLOB", "FITS", "", 0, 0, 0, 0, 0, 0, 0};
176static IBLOBVectorProperty imageBP = {mydev, "CCD_FITS_BLOB", "BLOB", COMM_GROUP,
177 IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};
178
179/* send client definitions of all properties */
180void ISInit()
181{
182 static int isInit=0;
183
184 if (isInit)
185 return;
186
187 /* USB by default {USB, SERIAL, PARALLEL, INET} */
188 portSwitchIndex = 0;
189
190 FLIImg = malloc (sizeof(img_t));
191
192 if (FLIImg == NULL)
193 {
194 IDMessage(mydev, "Error: unable to initialize driver. Low memory.");
195 IDLog("Error: unable to initialize driver. Low memory.");
196 return;
197 }
198
199 IEAddTimer (POLLMS, ISPoll, NULL);
200
201 isInit = 1;
202
203}
204
205void ISGetProperties (const char *dev)
206{
207
208 ISInit();
209
210 if (dev && strcmp (mydev, dev))
211 return;
212
213 /* COMM_GROUP */
214 IDDefSwitch(&ConnectSP, NULL);
215 IDDefSwitch(&PortSP, NULL);
216 IDDefBLOB(&imageBP, NULL);
217
218 /* Expose */
219 IDDefSwitch(&FrameTypeSP, NULL);
220 IDDefNumber(&ExposeTimeWNP, NULL);
221 IDDefNumber(&ExposeTimeRNP, NULL);
222 IDDefNumber(&TemperatureNP, NULL);
223
224 /* Image Group */
225 IDDefNumber(&FrameNP, NULL);
226 IDDefNumber(&BinningNP, NULL);
227
228}
229
230void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
231void ISSnoopDevice (XMLEle *root) {}
232
233void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
234{
235 long err;
236 int i;
237 ISwitch *sp;
238
239 /* ignore if not ours */
240 if (dev && strcmp (dev, mydev))
241 return;
242
243 ISInit();
244
245 /* Port type */
246 if (!strcmp (name, PortSP.name))
247 {
248 PortSP.s = IPS_IDLE;
249 IUResetSwitch(&PortSP);
250 IUUpdateSwitch(&PortSP, states, names, n);
251 portSwitchIndex = getOnSwitch(&PortSP);
252
253 PortSP.s = IPS_OK;
254 IDSetSwitch(&PortSP, NULL);
255 return;
256 }
257
258 /* Connection */
259 if (!strcmp (name, ConnectSP.name))
260 {
261 if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0)
262 return;
263 connectCCD();
264 return;
265 }
266
267 /* Frame Type */
268 if (!strcmp(FrameTypeSP.name, name))
269 {
270 if (checkPowerS(&FrameTypeSP))
271 return;
272
273 for (i = 0; i < n ; i++)
274 {
275 sp = IUFindSwitch(&FrameTypeSP, names[i]);
276
277 if (!sp)
278 {
279 FrameTypeSP.s = IPS_ALERT;
280 IDSetSwitch(&FrameTypeSP, "Unknown error. %s is not a member of %s property.", names[0], name);
281 return;
282 }
283
284 /* NORMAL, BIAS, or FLAT */
285 if ( (sp == &FrameTypeS[LIGHT_FRAME] || sp == &FrameTypeS[FLAT_FRAME]) && states[i] == ISS_ON)
286 {
287 if (sp == &FrameTypeS[LIGHT_FRAME])
288 FLIImg->frameType = LIGHT_FRAME;
289 else
290 FLIImg->frameType = FLAT_FRAME;
291
292 if ((err = FLISetFrameType(fli_dev, FLI_FRAME_TYPE_NORMAL) ))
293 {
294 IUResetSwitch(&FrameTypeSP);
295 FrameTypeS[LIGHT_FRAME].s = ISS_ON;
296 FrameTypeSP.s = IPS_ALERT;
297 IDSetSwitch(&FrameTypeSP, "FLISetFrameType() failed. %s.\n", strerror((int)-err));
298 IDLog("FLISetFrameType() failed. %s.\n", strerror((int)-err));
299 return;
300 }
301
302 IUResetSwitch(&FrameTypeSP);
303 sp->s = ISS_ON;
304 FrameTypeSP.s = IPS_OK;
305 IDSetSwitch(&FrameTypeSP, NULL);
306 break;
307 }
308 /* DARK AND BIAS */
309 else if ( (sp == &FrameTypeS[DARK_FRAME] || sp == &FrameTypeS[BIAS_FRAME]) && states[i] == ISS_ON)
310 {
311
312 if (sp == &FrameTypeS[DARK_FRAME])
313 FLIImg->frameType = DARK_FRAME;
314 else
315 FLIImg->frameType = BIAS_FRAME;
316
317 if ((err = FLISetFrameType(fli_dev, FLI_FRAME_TYPE_DARK) ))
318 {
319 IUResetSwitch(&FrameTypeSP);
320 FrameTypeS[LIGHT_FRAME].s = ISS_ON;
321 FrameTypeSP.s = IPS_ALERT;
322 IDSetSwitch(&FrameTypeSP, "FLISetFrameType() failed. %s.\n", strerror((int)-err));
323 IDLog("FLISetFrameType() failed. %s.\n", strerror((int)-err));
324 return;
325 }
326
327 IUResetSwitch(&FrameTypeSP);
328 sp->s = ISS_ON;
329 FrameTypeSP.s = IPS_OK;
330 IDSetSwitch(&FrameTypeSP, NULL);
331 break;
332 }
333
334 } /* For loop */
335
336 return;
337 }
338
339}
340
341void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
342{
343 ISInit();
344
345 /* ignore if not ours */
346 if (dev && strcmp (mydev, dev))
347 return;
348
349 /* suppress warning */
350 n=n; dev=dev; name=name; names=names; texts=texts;
351
352}
353
354
355void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
356{
357 long err;
358 int i;
359 INumber *np;
360 char errmsg[ERRMSG_SIZE];
361
362 /* ignore if not ours */
363 if (dev && strcmp (dev, mydev))
364 return;
365
366 ISInit();
367
368 /* Exposure time */
369 if (!strcmp (ExposeTimeWNP.name, name))
370 {
371 if (checkPowerN(&ExposeTimeWNP))
372 return;
373
374 if (ExposeTimeWNP.s == IPS_BUSY)
375 {
376 if ( (err = FLICancelExposure(fli_dev)))
377 {
378 ExposeTimeWNP.s = IPS_ALERT;
379 IDSetNumber(&ExposeTimeWNP, "FLICancelExposure() failed. %s.", strerror((int)-err));
380 IDLog("FLICancelExposure() failed. %s.\n", strerror((int)-err));
381 return;
382 }
383
384 ExposeTimeWNP.s = IPS_IDLE;
385 ExposeTimeRNP.s = IPS_IDLE;
386 ExposeTimeRN[0].value = 0;
387
388 IDSetNumber(&ExposeTimeWNP, "Exposure cancelled.");
389 IDSetNumber(&ExposeTimeRNP, NULL);
390 IDLog("Exposure Cancelled.\n");
391 return;
392 }
393
394 np = IUFindNumber(&ExposeTimeWNP, names[0]);
395
396 if (!np)
397 {
398 ExposeTimeWNP.s = IPS_ALERT;
399 IDSetNumber(&ExposeTimeWNP, "Error: %s is not a member of %s property.", names[0], name);
400 return;
401 }
402
403 np->value = values[0];
404 FLIImg->expose = (int) (values[0] * 1000.);
405
406 /* Set duration */
407 if ( (err = FLISetExposureTime(fli_dev, np->value * 1000.) ))
408 {
409 ExposeTimeWNP.s = IPS_ALERT;
410 IDSetNumber(&ExposeTimeWNP, "FLISetExposureTime() failed. %s.\n", strerror((int)-err));
411 IDLog("FLISetExposureTime() failed. %s.\n", strerror((int)-err));
412 return;
413 }
414
415 IDLog("Exposure Time (ms) is: %g\n", np->value * 1000.);
416
417 handleExposure(NULL);
418 return;
419 }
420
421
422 if (!strcmp(TemperatureNP.name, name))
423 {
424 if (checkPowerN(&TemperatureNP))
425 return;
426
427 TemperatureNP.s = IPS_IDLE;
428
429 np = IUFindNumber(&TemperatureNP, names[0]);
430
431 if (!np)
432 {
433 IDSetNumber(&TemperatureNP, "Unknown error. %s is not a member of %s property.", names[0], name);
434 return;
435 }
436
437 if (values[0] < MIN_CCD_TEMP || values[0] > MAX_CCD_TEMP)
438 {
439 IDSetNumber(&TemperatureNP, "Error: valid range of temperature is from %d to %d", MIN_CCD_TEMP, MAX_CCD_TEMP);
440 return;
441 }
442
443 if ( (err = FLISetTemperature(fli_dev, values[0])))
444 {
445 IDSetNumber(&TemperatureNP, "FLISetTemperature() failed. %s.", strerror((int)-err));
446 IDLog("FLISetTemperature() failed. %s.", strerror((int)-err));
447 return;
448 }
449
450 FLICam->temperature = values[0];
451 TemperatureNP.s = IPS_BUSY;
452
453 IDSetNumber(&TemperatureNP, "Setting CCD temperature to %+06.2f C", values[0]);
454 IDLog("Setting CCD temperature to %+06.2f C\n", values[0]);
455 return;
456 }
457
458 if (!strcmp(FrameNP.name, name))
459 {
460 int nset=0;
461
462 if (checkPowerN(&FrameNP))
463 return;
464
465 FrameNP.s = IPS_IDLE;
466
467 for (i=0; i < n ; i++)
468 {
469 np = IUFindNumber(&FrameNP, names[i]);
470
471 if (!np)
472 {
473 IDSetNumber(&FrameNP, "Unknown error. %s is not a member of %s property.", names[0], name);
474 return;
475 }
476
477 /* X or Width */
478 if (np == &FrameN[0] || np==&FrameN[2])
479 {
480 if (values[i] < 0 || values[i] > FLICam->width)
481 break;
482
483 nset++;
484 np->value = values[i];
485 }
486 /* Y or height */
487 else if (np == &FrameN[1] || np==&FrameN[3])
488 {
489 if (values[i] < 0 || values[i] > FLICam->height)
490 break;
491
492 nset++;
493 np->value = values[i];
494 }
495 }
496
497 if (nset < 4)
498 {
499 IDSetNumber(&FrameNP, "Invalid range. Valid range is (0,0) - (%0d,%0d)", FLICam->width, FLICam->height);
500 IDLog("Invalid range. Valid range is (0,0) - (%0d,%0d)", FLICam->width, FLICam->height);
501 return;
502 }
503
504 if (setImageArea(errmsg))
505 {
506 IDSetNumber(&FrameNP, "%s", errmsg);
507 return;
508 }
509
510 FrameNP.s = IPS_OK;
511
512 /* Adjusting image width and height */
513 FLIImg->width = FrameN[2].value;
514 FLIImg->height = FrameN[3].value;
515
516 IDSetNumber(&FrameNP, NULL);
517
518 } /* end FrameNP */
519
520
521 if (!strcmp(BinningNP.name, name))
522 {
523 if (checkPowerN(&BinningNP))
524 return;
525
526 BinningNP.s = IPS_IDLE;
527
528 for (i=0 ; i < n ; i++)
529 {
530 np = IUFindNumber(&BinningNP, names[i]);
531
532 if (!np)
533 {
534 IDSetNumber(&BinningNP, "Unknown error. %s is not a member of %s property.", names[0], name);
535 return;
536 }
537
538 /* X binning */
539 if (np == &BinningN[0])
540 {
541 if (values[i] < 1 || values[i] > MAX_X_BIN)
542 {
543 IDSetNumber(&BinningNP, "Error: Valid X bin values are from 1 to %g", MAX_X_BIN);
544 IDLog("Error: Valid X bin values are from 1 to %g", MAX_X_BIN);
545 return;
546 }
547
548 if ( (err = FLISetHBin(fli_dev, values[i])))
549 {
550 IDSetNumber(&BinningNP, "FLISetHBin() failed. %s.", strerror((int)-err));
551 IDLog("FLISetHBin() failed. %s.", strerror((int)-err));
552 return;
553 }
554
555 np->value = values[i];
556 }
557 else if (np == &BinningN[1])
558 {
559 if (values[i] < 1 || values[i] > MAX_Y_BIN)
560 {
561 IDSetNumber(&BinningNP, "Error: Valid Y bin values are from 1 to %g", MAX_Y_BIN);
562 IDLog("Error: Valid X bin values are from 1 to %g", MAX_Y_BIN);
563 return;
564 }
565
566 if ( (err = FLISetVBin(fli_dev, values[i])))
567 {
568 IDSetNumber(&BinningNP, "FLISetVBin() failed. %s.", strerror((int)-err));
569 IDLog("FLISetVBin() failed. %s.", strerror((int)-err));
570 return;
571 }
572
573 np->value = values[i];
574 }
575 } /* end for */
576
577 if (setImageArea(errmsg))
578 {
579 IDSetNumber(&BinningNP, errmsg, NULL);
580 IDLog("%s", errmsg);
581 return;
582 }
583
584 BinningNP.s = IPS_OK;
585
586 IDLog("Binning is: %.0f x %.0f\n", BinningN[0].value, BinningN[1].value);
587
588 IDSetNumber(&BinningNP, NULL);
589 return;
590 }
591
592}
593
594
595void ISPoll(void *p)
596{
597 long err;
598 long timeleft;
599 double ccdTemp;
600
601 if (!isCCDConnected())
602 {
603 IEAddTimer (POLLMS, ISPoll, NULL);
604 return;
605 }
606
607 /*IDLog("In Poll.\n");*/
608
609 switch (ExposeTimeWNP.s)
610 {
611 case IPS_IDLE:
612 break;
613
614 case IPS_OK:
615 break;
616
617 case IPS_BUSY:
618 if ( (err = FLIGetExposureStatus(fli_dev, &timeleft)))
619 {
620 ExposeTimeWNP.s = IPS_ALERT;
621 ExposeTimeRN[0].value = 0;
622
623 IDSetNumber(&ExposeTimeWNP, "FLIGetExposureStatus() failed. %s.", strerror((int)-err));
624 IDSetNumber(&ExposeTimeRNP, NULL);
625 IDLog("FLIGetExposureStatus() failed. %s.\n", strerror((int)-err));
626 break;
627 }
628
629 if (timeleft > 0)
630 {
631 ExposeTimeRN[0].value = timeleft / 1000.;
632 IDSetNumber(&ExposeTimeRNP, NULL);
633 break;
634 }
635
636 /* We're done exposing */
637 /*ExposeTimeWNP.s = IPS_OK;*/
638 ExposeTimeRNP.s = IPS_OK;
639 ExposeTimeRN[0].value = 0;
640 IDSetNumber(&ExposeTimeWNP, "Exposure done, downloading image...");
641 IDSetNumber(&ExposeTimeRNP, NULL);
642 IDLog("Exposure done, downloading image...\n");
643
644 /* grab and save image */
645 grabImage();
646
647 break;
648
649 case IPS_ALERT:
650 break;
651 }
652
653 switch (TemperatureNP.s)
654 {
655 case IPS_IDLE:
656 case IPS_OK:
657 if ( (err = FLIGetTemperature(fli_dev, &ccdTemp)))
658 {
659 TemperatureNP.s = IPS_IDLE;
660 IDSetNumber(&TemperatureNP, "FLIGetTemperature() failed. %s.", strerror((int)-err));
661 IDLog("FLIGetTemperature() failed. %s.", strerror((int)-err));
662 return;
663 }
664
665 if (fabs(TemperatureN[0].value - ccdTemp) >= TEMP_THRESHOLD)
666 {
667 TemperatureN[0].value = ccdTemp;
668 IDSetNumber(&TemperatureNP, NULL);
669 }
670 break;
671
672 case IPS_BUSY:
673 if ((err = FLIGetTemperature(fli_dev, &ccdTemp)))
674 {
675 TemperatureNP.s = IPS_ALERT;
676 IDSetNumber(&TemperatureNP, "FLIGetTemperature() failed. %s.", strerror((int)-err));
677 IDLog("FLIGetTemperature() failed. %s.", strerror((int)-err));
678 return;
679 }
680
681 if (fabs(FLICam->temperature - ccdTemp) <= TEMP_THRESHOLD)
682 TemperatureNP.s = IPS_OK;
683
684 TemperatureN[0].value = ccdTemp;
685 IDSetNumber(&TemperatureNP, NULL);
686 break;
687
688 case IPS_ALERT:
689 break;
690 }
691
692 p=p;
693
694 IEAddTimer (POLLMS, ISPoll, NULL);
695}
696
697/* Sets the Image area that the CCD will scan and download.
698 We compensate for binning. */
699int setImageArea(char errmsg[])
700{
701
702 long x_1, y_1, x_2, y_2;
703 long err;
704
705 /* Add the X and Y offsets */
706 x_1 = FrameN[0].value + FLICam->Visible_Area[0];
707 y_1 = FrameN[1].value + FLICam->Visible_Area[1];
708
709 x_2 = x_1 + (FrameN[2].value / BinningN[0].value);
710 y_2 = y_1 + (FrameN[3].value / BinningN[1].value);
711
712 if (x_2 > FLICam->Visible_Area[2])
713 x_2 = FLICam->Visible_Area[2];
714
715 if (y_2 > FLICam->Visible_Area[3])
716 y_2 = FLICam->Visible_Area[3];
717
718 IDLog("The Final image area is (%ld, %ld), (%ld, %ld)\n", x_1, y_1, x_2, y_2);
719
720 FLIImg->width = x_2 - x_1;
721 FLIImg->height = y_2 - y_1;
722
723 if ( (err = FLISetImageArea(fli_dev, x_1, y_1, x_2, y_2) ))
724 {
725 snprintf(errmsg, ERRMSG_SIZE, "FLISetImageArea() failed. %s.\n", strerror((int)-err));
726 IDLog("%s", errmsg);
727 return -1;
728 }
729
730 return 0;
731}
732
733/* Downloads the image from the CCD row by row and store them
734 in a raw file.
735 N.B. No processing is done on the image */
736int grabImage()
737{
738 long err;
739 int img_size,i, fd;
740 char errmsg[ERRMSG_SIZE];
741 char filename[TEMPFILE_LEN] = "/tmp/fitsXXXXXX";
742
743 if ((fd = mkstemp(filename)) < 0)
744 {
745 IDMessage(mydev, "Error making temporary filename.");
746 IDLog("Error making temporary filename.\n");
747 return -1;
748 }
749 close(fd);
750
751 img_size = FLIImg->width * FLIImg->height * sizeof(unsigned short);
752
753 FLIImg->img = malloc (img_size);
754
755 if (FLIImg->img == NULL)
756 {
757 IDMessage(mydev, "Not enough memory to store image.");
758 IDLog("Not enough memory to store image.\n");
759 return -1;
760 }
761
762 for (i=0; i < FLIImg->height ; i++)
763 {
764 if ( (err = FLIGrabRow(fli_dev, &FLIImg->img[i * FLIImg->width], FLIImg->width)))
765 {
766 free(FLIImg->img);
767 IDMessage(mydev, "FLIGrabRow() failed at row %d. %s.", i, strerror((int)-err));
768 IDLog("FLIGrabRow() failed at row %d. %s.\n", i, strerror((int)-err));
769 return -1;
770 }
771 }
772
773 IDMessage(mydev, "Download complete.\n");
774
775 /*err = (ImageFormatS[0].s == ISS_ON) ? writeFITS(FileNameT[0].text, errmsg) : writeRAW(FileNameT[0].text, errmsg);*/
776 err = writeFITS(filename, errmsg);
777
778 if (err)
779 {
780 free(FLIImg->img);
781 IDMessage(mydev, errmsg, NULL);
782 return -1;
783 }
784
785 free(FLIImg->img);
786 return 0;
787
788}
789
790int writeFITS(const char* filename, char errmsg[])
791{
792 fitsfile *fptr; /* pointer to the FITS file; defined in fitsio.h */
793 int status;
794 long fpixel = 1, naxis = 2, nelements;
795 long naxes[2];
796 char filename_rw[TEMPFILE_LEN+1];
797
798 naxes[0] = FLIImg->width;
799 naxes[1] = FLIImg->height;
800
801 /* Append ! to file name to over write it.*/
802 snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename);
803
804 status = 0; /* initialize status before calling fitsio routines */
805 fits_create_file(&fptr, filename_rw, &status); /* create new file */
806
807 /* Create the primary array image (16-bit short integer pixels */
808 fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);
809
810 addFITSKeywords(fptr);
811
812 nelements = naxes[0] * naxes[1]; /* number of pixels to write */
813
814 /* Write the array of integers to the image */
815 fits_write_img(fptr, TUSHORT, fpixel, nelements, FLIImg->img, &status);
816
817 fits_close_file(fptr, &status); /* close the file */
818
819 fits_report_error(stderr, status); /* print out any error messages */
820
821 /* Success */
822 ExposeTimeWNP.s = IPS_OK;
823 IDSetNumber(&ExposeTimeWNP, NULL);
824 uploadFile(filename);
825 unlink(filename);
826
827 return status;
828}
829
830void addFITSKeywords(fitsfile *fptr)
831{
832 int status=0;
833 char binning_s[32];
834 char frame_s[32];
835 double min_val, max_val;
836
837 /*pixel_size = (float) PixelSizeN[0].value;
838 min_val = min();
839 max_val = max();
840 temp = (float) TemperatureN[0].value;
841 expose = (float) FLIImg->expose;*/
842
843 snprintf(binning_s, 32, "(%g x %g)", BinningN[0].value, BinningN[1].value);
844
845 switch (FLIImg->frameType)
846 {
847 case LIGHT_FRAME:
848 strcpy(frame_s, "Light");
849 break;
850 case BIAS_FRAME:
851 strcpy(frame_s, "Bias");
852 break;
853 case FLAT_FRAME:
854 strcpy(frame_s, "Flat Field");
855 break;
856 case DARK_FRAME:
857 strcpy(frame_s, "Dark");
858 break;
859 }
860
861 fits_update_key(fptr, TDOUBLE, "CCD-TEMP", &(TemperatureN[0].value), "CCD Temperature (Celcius)", &status);
862 fits_update_key(fptr, TDOUBLE, "EXPOSURE", &(FLIImg->expose), "Total Exposure Time (ms)", &status);
863 fits_update_key(fptr, TDOUBLE, "PIX-SIZ", &(PixelSizeN[0].value), "Pixel Size (microns)", &status);
864 fits_update_key(fptr, TSTRING, "BINNING", binning_s, "Binning HOR x VER", &status);
865 fits_update_key(fptr, TSTRING, "FRAME", frame_s, "Frame Type", &status);
866 fits_update_key(fptr, TDOUBLE, "DATAMIN", &min_val, "Minimum value", &status);
867 fits_update_key(fptr, TDOUBLE, "DATAMAX", &max_val, "Maximum value", &status);
868 fits_update_key(fptr, TSTRING, "INSTRUME", "Finger Lakes Instruments", "CCD Name", &status);
869 fits_write_date(fptr, &status);
870
871}
872
873void uploadFile(const char* filename)
874{
875 FILE * fitsFile;
876 unsigned char *fitsData, *compressedData;
877 int r=0;
878 unsigned int i =0, nr = 0;
879 uLongf compressedBytes=0;
880 uLong totalBytes;
881 struct stat stat_p;
882
883 if ( -1 == stat (filename, &stat_p))
884 {
885 IDLog(" Error occurred attempting to stat file.\n");
886 return;
887 }
888
889 totalBytes = stat_p.st_size;
890 fitsData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
891 compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
892
893 if (fitsData == NULL || compressedData == NULL)
894 {
895 if (fitsData) free(fitsData);
896 if (compressedData) free(compressedData);
897 IDLog("Error! low memory. Unable to initialize fits buffers.\n");
898 return;
899 }
900
901 fitsFile = fopen(filename, "r");
902
903 if (fitsFile == NULL)
904 return;
905
906 /* #1 Read file from disk */
907 for (i=0; i < totalBytes; i+= nr)
908 {
909 nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
910
911 if (nr <= 0)
912 {
913 IDLog("Error reading temporary FITS file.\n");
914 return;
915 }
916 }
917 fclose(fitsFile);
918
919 compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
920
921 /* #2 Compress it */
922 r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9);
923 if (r != Z_OK)
924 {
925 /* this should NEVER happen */
926 IDLog("internal error - compression failed: %d\n", r);
927 return;
928 }
929
930 /* #3 Send it */
931 imageB.blob = compressedData;
932 imageB.bloblen = compressedBytes;
933 imageB.size = totalBytes;
934 strcpy(imageB.format, ".fits.z");
935 imageBP.s = IPS_OK;
936 IDSetBLOB (&imageBP, NULL);
937
938 free (fitsData);
939 free (compressedData);
940
941}
942
943/* Initiates the exposure procedure */
944void handleExposure(void *p)
945{
946 long err;
947
948 /* no warning */
949 p=p;
950
951 /* BIAS frame is the same as DARK but with minimum period. i.e. readout from camera electronics.
952 */
953 if (FLIImg->frameType == BIAS_FRAME)
954 {
955 if ((err = FLISetExposureTime(fli_dev, 50)))
956 {
957 ExposeTimeWNP.s = IPS_ALERT;
958 IDSetNumber(&ExposeTimeWNP, "FLISetExposureTime() failed. %s.\n", strerror((int)-err));
959 IDLog("FLISetExposureTime() failed. %s.\n", strerror((int)-err));
960 return;
961 }
962 }
963
964 if ((err = FLIExposeFrame(fli_dev)))
965 {
966 ExposeTimeWNP.s = IPS_ALERT;
967 IDSetNumber(&ExposeTimeWNP, "FLIExposeFrame() failed. %s.", strerror((int)-err));
968 IDLog("FLIExposeFrame() failed. %s.\n", strerror((int)-err));
969 return;
970 }
971
972 ExposeTimeWNP.s = IPS_BUSY;
973
974 IDSetNumber(&ExposeTimeWNP, "Taking a %g seconds frame...", FLIImg->expose / 1000.);
975
976 IDLog("Taking a frame...\n");
977}
978
979/* Retrieves basic data from the CCD upon connection like temperature, array size, firmware..etc */
980void getBasicData()
981{
982
983 char buff[2048];
984 long err;
985
986 IDLog("In getBasicData()\n");
987
988 if ((err = FLIGetModel (fli_dev, buff, 2048)))
989 {
990 IDMessage(mydev, "FLIGetModel() failed. %s.", strerror((int)-err));
991 IDLog("FLIGetModel() failed. %s.\n", strerror((int)-err));
992 return;
993 }
994 else
995 {
996 if ( (FLICam->model = malloc (sizeof(char) * 2048)) == NULL)
997 {
998 IDMessage(mydev, "malloc() failed.");
999 IDLog("malloc() failed.");
1000 return;
1001 }
1002
1003 strcpy(FLICam->model, buff);
1004 }
1005
1006 if (( err = FLIGetHWRevision(fli_dev, &FLICam->HWRevision)))
1007 {
1008 IDMessage(mydev, "FLIGetHWRevision() failed. %s.", strerror((int)-err));
1009 IDLog("FLIGetHWRevision() failed. %s.\n", strerror((int)-err));
1010
1011 return;
1012 }
1013
1014 if (( err = FLIGetFWRevision(fli_dev, &FLICam->FWRevision)))
1015 {
1016 IDMessage(mydev, "FLIGetFWRevision() failed. %s.", strerror((int)-err));
1017 IDLog("FLIGetFWRevision() failed. %s.\n", strerror((int)-err));
1018 return;
1019 }
1020
1021 if (( err = FLIGetPixelSize(fli_dev, &FLICam->x_pixel_size, &FLICam->y_pixel_size)))
1022 {
1023 IDMessage(mydev, "FLIGetPixelSize() failed. %s.", strerror((int)-err));
1024 IDLog("FLIGetPixelSize() failed. %s.\n", strerror((int)-err));
1025 return;
1026 }
1027
1028 FLICam->x_pixel_size *= 1e6;
1029 FLICam->y_pixel_size *= 1e6;
1030
1031 if (( err = FLIGetArrayArea(fli_dev, &FLICam->Array_Area[0], &FLICam->Array_Area[1], &FLICam->Array_Area[2], &FLICam->Array_Area[3])))
1032 {
1033 IDMessage(mydev, "FLIGetArrayArea() failed. %s.", strerror((int)-err));
1034 IDLog("FLIGetArrayArea() failed. %s.\n", strerror((int)-err));
1035 return;
1036 }
1037
1038 if (( err = FLIGetVisibleArea( fli_dev, &FLICam->Visible_Area[0], &FLICam->Visible_Area[1], &FLICam->Visible_Area[2], &FLICam->Visible_Area[3])))
1039 {
1040 IDMessage(mydev, "FLIGetVisibleArea() failed. %s.", strerror((int)-err));
1041 IDLog("FLIGetVisibleArea() failed. %s.\n", strerror((int)-err));
1042 }
1043
1044 if (( err = FLIGetTemperature(fli_dev, &FLICam->temperature)))
1045 {
1046 IDMessage(mydev, "FLIGetTemperature() failed. %s.", strerror((int)-err));
1047 IDLog("FLIGetTemperature() failed. %s.\n", strerror((int)-err));
1048 return;
1049 }
1050
1051 IDLog("The CCD Temperature is %f.\n", FLICam->temperature);
1052
1053 PixelSizeN[0].value = FLICam->x_pixel_size; /* Pixel width (um) */
1054 PixelSizeN[1].value = FLICam->y_pixel_size; /* Pixel height (um) */
1055 TemperatureN[0].value = FLICam->temperature; /* CCD chip temperatre (degrees C) */
1056 FrameN[0].value = 0; /* X */
1057 FrameN[1].value = 0; /* Y */
1058 FrameN[2].value = FLICam->Visible_Area[2] - FLICam->Visible_Area[0]; /* Frame Width */
1059 FrameN[3].value = FLICam->Visible_Area[3] - FLICam->Visible_Area[1]; /* Frame Height */
1060
1061 FLICam->width = FLIImg->width = FrameN[2].value;
1062 FLICam->height = FLIImg->width = FrameN[3].value;
1063
1064 BinningN[0].value = BinningN[1].value = 1;
1065
1066 IDLog("The Camera Width is %d ---- %d\n", (int) FLICam->width, (int) FrameN[2].value);
1067 IDLog("The Camera Height is %d ---- %d\n", (int) FLICam->height, (int) FrameN[3].value);
1068
1069 IDSetNumber(&PixelSizeNP, NULL);
1070 IDSetNumber(&TemperatureNP, NULL);
1071 IDSetNumber(&FrameNP, NULL);
1072 IDSetNumber(&BinningNP, NULL);
1073
1074 IDLog("Exiting getBasicData()\n");
1075
1076}
1077
1078int manageDefaults(char errmsg[])
1079{
1080 long err;
1081 /*int exposeTimeMS;
1082
1083 exposeTimeMS = (int) (ExposeTimeWN[0].value * 1000.);
1084
1085 IDLog("Setting default exposure time of %d ms.\n", exposeTimeMS);
1086 if ( (err = FLISetExposureTime(fli_dev, exposeTimeMS) ))
1087 {
1088 snprintf(errmsg, ERRMSG_SIZE, "FLISetExposureTime() failed. %s.\n", strerror((int)-err));
1089 IDLog(errmsg, NULL);
1090 return -1;
1091 }*/
1092
1093 /* Default frame type is NORMAL */
1094 if ( (err = FLISetFrameType(fli_dev, FLI_FRAME_TYPE_NORMAL) ))
1095 {
1096 snprintf(errmsg, ERRMSG_SIZE, "FLISetFrameType() failed. %s.\n", strerror((int)-err));
1097 IDLog(errmsg, NULL);
1098 return -1;
1099 }
1100
1101 /* X horizontal binning */
1102 if ( (err = FLISetHBin(fli_dev, BinningN[0].value) ))
1103 {
1104 snprintf(errmsg, ERRMSG_SIZE, "FLISetBin() failed. %s.\n", strerror((int)-err));
1105 IDLog(errmsg, NULL);
1106 return -1;
1107 }
1108
1109 /* Y vertical binning */
1110 if ( (err = FLISetVBin(fli_dev, BinningN[1].value) ))
1111 {
1112 snprintf(errmsg, ERRMSG_SIZE, "FLISetVBin() failed. %s.\n", strerror((int)-err));
1113 IDLog(errmsg, NULL);
1114 return -1;
1115 }
1116
1117 IDLog("Setting default binning %f x %f.\n", BinningN[0].value, BinningN[1].value);
1118
1119 FLISetNFlushes(fli_dev, NFLUSHES);
1120
1121 /* Set image area */
1122 if (setImageArea(errmsg))
1123 return -1;
1124
1125 /* Success */
1126 return 0;
1127
1128}
1129
1130int getOnSwitch(ISwitchVectorProperty *sp)
1131{
1132 int i=0;
1133 for (i=0; i < sp->nsp ; i++)
1134 {
1135 /*IDLog("Switch %s is %s\n", sp->sp[i].name, sp->sp[i].s == ISS_ON ? "On" : "Off");*/
1136 if (sp->sp[i].s == ISS_ON)
1137 return i;
1138 }
1139
1140 return -1;
1141}
1142
1143int checkPowerS(ISwitchVectorProperty *sp)
1144{
1145 if (ConnectSP.s != IPS_OK)
1146 {
1147 if (!strcmp(sp->label, ""))
1148 IDMessage (mydev, "Cannot change property %s while the CCD is offline.", sp->name);
1149 else
1150 IDMessage (mydev, "Cannot change property %s while the CCD is offline.", sp->label);
1151
1152 sp->s = IPS_IDLE;
1153 IDSetSwitch(sp, NULL);
1154 return -1;
1155 }
1156
1157 return 0;
1158}
1159
1160int checkPowerN(INumberVectorProperty *np)
1161{
1162 if (ConnectSP.s != IPS_OK)
1163 {
1164 if (!strcmp(np->label, ""))
1165 IDMessage (mydev, "Cannot change property %s while the CCD is offline.", np->name);
1166 else
1167 IDMessage (mydev, "Cannot change property %s while the CCD is offline.", np->label);
1168
1169 np->s = IPS_IDLE;
1170 IDSetNumber(np, NULL);
1171 return -1;
1172 }
1173
1174 return 0;
1175}
1176
1177int checkPowerT(ITextVectorProperty *tp)
1178{
1179
1180 if (ConnectSP.s != IPS_OK)
1181 {
1182 if (!strcmp(tp->label, ""))
1183 IDMessage (mydev, "Cannot change property %s while the CCD is offline.", tp->name);
1184 else
1185 IDMessage (mydev, "Cannot change property %s while the CCD is offline.", tp->label);
1186
1187 tp->s = IPS_IDLE;
1188 IDSetText(tp, NULL);
1189 return -1;
1190 }
1191
1192 return 0;
1193
1194}
1195
1196void connectCCD()
1197{
1198 long err;
1199 char errmsg[ERRMSG_SIZE];
1200
1201 IDLog ("In ConnectCCD\n");
1202
1203 /* USB by default {USB, SERIAL, PARALLEL, INET} */
1204 switch (ConnectS[0].s)
1205 {
1206 case ISS_ON:
1207 IDLog("Current portSwitch is %d\n", portSwitchIndex);
1208 IDLog("Attempting to find the camera in domain %ld\n", Domains[portSwitchIndex]);
1209 if (findcam(Domains[portSwitchIndex])) {
1210 ConnectSP.s = IPS_IDLE;
1211 ConnectS[0].s = ISS_OFF;
1212 ConnectS[1].s = ISS_ON;
1213 IDSetSwitch(&ConnectSP, "Error: no cameras were detected.");
1214 IDLog("Error: no cameras were detected.\n");
1215 return;
1216 }
1217
1218 if ((err = FLIOpen(&fli_dev, FLICam->name, FLIDEVICE_CAMERA | FLICam->domain)))
1219 {
1220 ConnectSP.s = IPS_IDLE;
1221 ConnectS[0].s = ISS_OFF;
1222 ConnectS[1].s = ISS_ON;
1223 IDSetSwitch(&ConnectSP, "Error: FLIOpen() failed. %s.", strerror( (int) -err));
1224 IDLog("Error: FLIOpen() failed. %s.\n", strerror( (int) -err));
1225 return;
1226 }
1227
1228 /* Sucess! */
1229 ConnectS[0].s = ISS_ON;
1230 ConnectS[1].s = ISS_OFF;
1231 ConnectSP.s = IPS_OK;
1232 IDSetSwitch(&ConnectSP, "CCD is online. Retrieving basic data.");
1233 IDLog("CCD is online. Retrieving basic data.\n");
1234 getBasicData();
1235 if (manageDefaults(errmsg))
1236 {
1237 IDMessage(mydev, errmsg, NULL);
1238 IDLog("%s", errmsg);
1239 return;
1240 }
1241
1242 break;
1243
1244 case ISS_OFF:
1245 ConnectS[0].s = ISS_OFF;
1246 ConnectS[1].s = ISS_ON;
1247 ConnectSP.s = IPS_IDLE;
1248 if ((err = FLIClose(fli_dev))) {
1249 ConnectSP.s = IPS_IDLE;
1250 ConnectS[0].s = ISS_OFF;
1251 ConnectS[1].s = ISS_ON;
1252 IDSetSwitch(&ConnectSP, "Error: FLIClose() failed. %s.", strerror( (int) -err));
1253 IDLog("Error: FLIClose() failed. %s.\n", strerror( (int) -err));
1254 return;
1255 }
1256 IDSetSwitch(&ConnectSP, "CCD is offline.");
1257 break;
1258 }
1259}
1260
1261/* isCCDConnected: return 1 if we have a connection, 0 otherwise */
1262int isCCDConnected(void)
1263{
1264 return ((ConnectS[0].s == ISS_ON) ? 1 : 0);
1265}
1266
1267int findcam(flidomain_t domain)
1268{
1269 char **tmplist;
1270 long err;
1271
1272 IDLog("In find Camera, the domain is %ld\n", domain);
1273
1274 if (( err = FLIList(domain | FLIDEVICE_CAMERA, &tmplist)))
1275 {
1276 IDLog("FLIList() failed. %s\n", strerror((int)-err));
1277 return -1;
1278 }
1279
1280 if (tmplist != NULL && tmplist[0] != NULL)
1281 {
1282 int i;
1283
1284 IDLog("Trying to allocate memory to FLICam\n");
1285 if ((FLICam = malloc (sizeof (cam_t))) == NULL)
1286 {
1287 IDLog("malloc() failed.\n");
1288 return -1;
1289 }
1290
1291 for (i = 0; tmplist[i] != NULL; i++)
1292 {
1293 int j;
1294
1295 for (j = 0; tmplist[i][j] != '\0'; j++)
1296 if (tmplist[i][j] == ';')
1297 {
1298 tmplist[i][j] = '\0';
1299 break;
1300 }
1301 }
1302
1303 FLICam->domain = domain;
1304
1305 switch (domain)
1306 {
1307 case FLIDOMAIN_PARALLEL_PORT:
1308 FLICam->dname = strdup("parallel port");
1309 break;
1310
1311 case FLIDOMAIN_USB:
1312 FLICam->dname = strdup("USB");
1313 break;
1314
1315 case FLIDOMAIN_SERIAL:
1316 FLICam->dname = strdup("serial");
1317 break;
1318
1319 case FLIDOMAIN_INET:
1320 FLICam->dname = strdup("inet");
1321 break;
1322
1323 default:
1324 FLICam->dname = strdup("Unknown domain");
1325 }
1326
1327 FLICam->name = strdup(tmplist[0]);
1328
1329 if ((err = FLIFreeList(tmplist)))
1330 {
1331 IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
1332 return -1;
1333 }
1334
1335 } /* end if */
1336 else
1337 {
1338 if ((err = FLIFreeList(tmplist)))
1339 {
1340 IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err));
1341 return -1;
1342 }
1343
1344 return -1;
1345 }
1346
1347 IDLog("Findcam() finished successfully.\n");
1348 return 0;
1349}
1350
1351double min()
1352{
1353 double lmin = FLIImg->img[0];
1354 int ind=0, i, j;
1355
1356 for (i= 0; i < FLIImg->height ; i++)
1357 for (j= 0; j < FLIImg->width; j++)
1358 {
1359 ind = (i * FLIImg->width) + j;
1360 if (FLIImg->img[ind] < lmin) lmin = FLIImg->img[ind];
1361 }
1362
1363 return lmin;
1364}
1365
1366double max()
1367{
1368 double lmax = FLIImg->img[0];
1369 int ind=0, i, j;
1370
1371 for (i= 0; i < FLIImg->height ; i++)
1372 for (j= 0; j < FLIImg->width; j++)
1373 {
1374 ind = (i * FLIImg->width) + j;
1375 if (FLIImg->img[ind] > lmax) lmax = FLIImg->img[ind];
1376 }
1377
1378 return lmax;
1379}
Note: See TracBrowser for help on using the repository browser.